001/* 002 * The contents of this file are subject to the terms of the Common Development and 003 * Distribution License (the License). You may not use this file except in compliance with the 004 * License. 005 * 006 * You can obtain a copy of the License at legal/CDDLv1.0.txt. See the License for the 007 * specific language governing permission and limitations under the License. 008 * 009 * When distributing Covered Software, include this CDDL Header Notice in each file and include 010 * the License file at legal/CDDLv1.0.txt. If applicable, add the following below the CDDL 011 * Header, with the fields enclosed by brackets [] replaced by your own identifying 012 * information: "Portions Copyright [year] [name of copyright owner]". 013 * 014 * Copyright 2008-2010 Sun Microsystems, Inc. 015 * Portions Copyright 2013-2016 ForgeRock AS. 016 */ 017 018package org.opends.guitools.controlpanel.task; 019 020import static org.opends.messages.AdminToolMessages.*; 021 022import java.util.ArrayList; 023import java.util.Collection; 024import java.util.HashSet; 025import java.util.LinkedHashSet; 026import java.util.Set; 027import java.util.TreeSet; 028 029import javax.naming.NamingEnumeration; 030import javax.naming.NamingException; 031import javax.naming.directory.Attribute; 032import javax.naming.directory.BasicAttribute; 033import javax.naming.directory.DirContext; 034import javax.naming.directory.ModificationItem; 035import javax.naming.directory.SearchControls; 036import javax.naming.directory.SearchResult; 037import javax.swing.SwingUtilities; 038 039import org.opends.admin.ads.util.ConnectionUtils; 040import org.opends.guitools.controlpanel.browser.BrowserController; 041import org.opends.guitools.controlpanel.datamodel.BackendDescriptor; 042import org.opends.guitools.controlpanel.datamodel.BaseDNDescriptor; 043import org.opends.guitools.controlpanel.datamodel.ControlPanelInfo; 044import org.opends.guitools.controlpanel.ui.ColorAndFontConstants; 045import org.opends.guitools.controlpanel.ui.ProgressDialog; 046import org.opends.guitools.controlpanel.util.Utilities; 047import org.opends.messages.AdminToolMessages; 048import org.forgerock.i18n.LocalizableMessage; 049import org.forgerock.opendj.ldap.DN; 050import org.opends.server.util.ServerConstants; 051 052/** The class that is in charge of adding a set of entries to a set of static groups. */ 053public class AddToGroupTask extends Task 054{ 055 private Set<String> backendSet; 056 private LinkedHashSet<DN> dns = new LinkedHashSet<>(); 057 private LinkedHashSet<DN> groupDns = new LinkedHashSet<>(); 058 059 /** 060 * Constructor of the task. 061 * @param info the control panel information. 062 * @param dlg the progress dialog where the task progress will be displayed. 063 * @param dns the DNs of the entries we want to add to the groups. 064 * @param groupDns the groups that we want to modify. 065 */ 066 public AddToGroupTask(ControlPanelInfo info, ProgressDialog dlg, 067 Set<DN> dns, Set<DN> groupDns) 068 { 069 super(info, dlg); 070 backendSet = new HashSet<>(); 071 this.dns.addAll(dns); 072 this.groupDns.addAll(groupDns); 073 for (DN groupDn : groupDns) 074 { 075 for (BackendDescriptor backend : 076 info.getServerDescriptor().getBackends()) 077 { 078 for (BaseDNDescriptor baseDN : backend.getBaseDns()) 079 { 080 if (groupDn.isSubordinateOrEqualTo(baseDN.getDn())) 081 { 082 backendSet.add(backend.getBackendID()); 083 } 084 } 085 } 086 } 087 } 088 089 @Override 090 public Type getType() 091 { 092 return Type.MODIFY_ENTRY; 093 } 094 095 @Override 096 public Set<String> getBackends() 097 { 098 return backendSet; 099 } 100 101 @Override 102 public LocalizableMessage getTaskDescription() 103 { 104 return AdminToolMessages.INFO_CTRL_PANEL_ADD_TO_GROUP_TASK_DESCRIPTION.get(); 105 } 106 107 @Override 108 protected String getCommandLinePath() 109 { 110 return null; 111 } 112 113 @Override 114 protected ArrayList<String> getCommandLineArguments() 115 { 116 return new ArrayList<>(); 117 } 118 119 @Override 120 public boolean canLaunch(Task taskToBeLaunched, 121 Collection<LocalizableMessage> incompatibilityReasons) 122 { 123 if (!isServerRunning() 124 && state == State.RUNNING 125 && runningOnSameServer(taskToBeLaunched)) 126 { 127 // All the operations are incompatible if they apply to this 128 // backend for safety. This is a short operation so the limitation 129 // has not a lot of impact. 130 Set<String> backends = new TreeSet<>(taskToBeLaunched.getBackends()); 131 backends.retainAll(getBackends()); 132 if (!backends.isEmpty()) 133 { 134 incompatibilityReasons.add(getIncompatibilityMessage(this, taskToBeLaunched)); 135 return false; 136 } 137 } 138 return true; 139 } 140 141 @Override 142 public boolean regenerateDescriptor() 143 { 144 return false; 145 } 146 147 @Override 148 public void runTask() 149 { 150 state = State.RUNNING; 151 lastException = null; 152 153 try 154 { 155 for (final DN groupDn : groupDns) 156 { 157 final Collection<ModificationItem> modifications = 158 getModifications(groupDn, dns); 159 if (!modifications.isEmpty()) 160 { 161 ModificationItem[] mods = 162 new ModificationItem[modifications.size()]; 163 modifications.toArray(mods); 164 165 SwingUtilities.invokeLater(new Runnable() 166 { 167 @Override 168 public void run() 169 { 170 printEquivalentCommandToModify(groupDn, modifications, false); 171 getProgressDialog().appendProgressHtml( 172 Utilities.getProgressWithPoints( 173 INFO_CTRL_PANEL_ADDING_TO_GROUP.get(groupDn), 174 ColorAndFontConstants.progressFont)); 175 } 176 }); 177 178 getInfo().getConnection().getLdapContext().modifyAttributes( 179 Utilities.getJNDIName(groupDn.toString()), mods); 180 181 SwingUtilities.invokeLater(new Runnable() 182 { 183 @Override 184 public void run() 185 { 186 getProgressDialog().appendProgressHtml( 187 Utilities.getProgressDone( 188 ColorAndFontConstants.progressFont)); 189 } 190 }); 191 } 192 } 193 state = State.FINISHED_SUCCESSFULLY; 194 } 195 catch (Throwable t) 196 { 197 lastException = t; 198 state = State.FINISHED_WITH_ERROR; 199 } 200 } 201 202 /** 203 * Returns the modifications that must be made to the provided group. 204 * @param groupDn the DN of the static group that must be updated. 205 * @param dns the list of entry DNs that must be added to the group. 206 * @return the list of modifications (in form of ModificationItem) that 207 * must be made to the provided group. 208 * @throws NamingException if an error occurs. 209 */ 210 private Collection<ModificationItem> getModifications(DN groupDn, 211 Set<DN> dns) throws NamingException 212 { 213 ArrayList<ModificationItem> modifications = new ArrayList<>(); 214 215 // Search for the group entry 216 SearchControls ctls = new SearchControls(); 217 ctls.setSearchScope(SearchControls.OBJECT_SCOPE); 218 ctls.setReturningAttributes( 219 new String[] { 220 ServerConstants.OBJECTCLASS_ATTRIBUTE_TYPE_NAME, 221 ServerConstants.ATTR_MEMBER, 222 ServerConstants.ATTR_UNIQUE_MEMBER 223 }); 224 String filter = BrowserController.ALL_OBJECTS_FILTER; 225 NamingEnumeration<SearchResult> result = 226 getInfo().getConnection().getLdapContext().search( 227 Utilities.getJNDIName(groupDn.toString()), 228 filter, ctls); 229 230 try 231 { 232 String memberAttr = ServerConstants.ATTR_MEMBER; 233 while (result.hasMore()) 234 { 235 SearchResult sr = result.next(); 236 Set<String> objectClasses = 237 ConnectionUtils.getValues(sr, ServerConstants 238 .OBJECTCLASS_ATTRIBUTE_TYPE_NAME); 239 if (objectClasses.contains(ServerConstants.OC_GROUP_OF_UNIQUE_NAMES)) 240 { 241 memberAttr = ServerConstants.ATTR_UNIQUE_MEMBER; 242 } 243 Set<String> values = ConnectionUtils.getValues(sr, memberAttr); 244 Set<String> dnsToAdd = new LinkedHashSet<>(); 245 if (values != null) 246 { 247 for (DN newDn : dns) 248 { 249 boolean found = false; 250 for (String dn : values) 251 { 252 if (Utilities.areDnsEqual(dn, newDn.toString())) 253 { 254 found = true; 255 break; 256 } 257 } 258 if (!found) 259 { 260 dnsToAdd.add(newDn.toString()); 261 } 262 } 263 } 264 else 265 { 266 for (DN newDn : dns) 267 { 268 dnsToAdd.add(newDn.toString()); 269 } 270 } 271 if (!dnsToAdd.isEmpty()) 272 { 273 Attribute attribute = new BasicAttribute(memberAttr); 274 for (String dn : dnsToAdd) 275 { 276 attribute.add(dn); 277 } 278 modifications.add(new ModificationItem( 279 DirContext.ADD_ATTRIBUTE, 280 attribute)); 281 } 282 } 283 } 284 finally 285 { 286 result.close(); 287 } 288 return modifications; 289 } 290} 291