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