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/** 053 * The class that is in charge of adding a set of entries to a set of static 054 * groups. 055 */ 056public class AddToGroupTask extends Task 057{ 058 private Set<String> backendSet; 059 private LinkedHashSet<DN> dns = new LinkedHashSet<>(); 060 private LinkedHashSet<DN> groupDns = new LinkedHashSet<>(); 061 062 /** 063 * Constructor of the task. 064 * @param info the control panel information. 065 * @param dlg the progress dialog where the task progress will be displayed. 066 * @param dns the DNs of the entries we want to add to the groups. 067 * @param groupDns the groups that we want to modify. 068 */ 069 public AddToGroupTask(ControlPanelInfo info, ProgressDialog dlg, 070 Set<DN> dns, Set<DN> groupDns) 071 { 072 super(info, dlg); 073 backendSet = new HashSet<>(); 074 this.dns.addAll(dns); 075 this.groupDns.addAll(groupDns); 076 for (DN groupDn : groupDns) 077 { 078 for (BackendDescriptor backend : 079 info.getServerDescriptor().getBackends()) 080 { 081 for (BaseDNDescriptor baseDN : backend.getBaseDns()) 082 { 083 if (groupDn.isSubordinateOrEqualTo(baseDN.getDn())) 084 { 085 backendSet.add(backend.getBackendID()); 086 } 087 } 088 } 089 } 090 } 091 092 /** {@inheritDoc} */ 093 public Type getType() 094 { 095 return Type.MODIFY_ENTRY; 096 } 097 098 /** {@inheritDoc} */ 099 public Set<String> getBackends() 100 { 101 return backendSet; 102 } 103 104 /** {@inheritDoc} */ 105 public LocalizableMessage getTaskDescription() 106 { 107 return AdminToolMessages.INFO_CTRL_PANEL_ADD_TO_GROUP_TASK_DESCRIPTION.get(); 108 } 109 110 /** {@inheritDoc} */ 111 protected String getCommandLinePath() 112 { 113 return null; 114 } 115 116 /** {@inheritDoc} */ 117 protected ArrayList<String> getCommandLineArguments() 118 { 119 return new ArrayList<>(); 120 } 121 122 /** {@inheritDoc} */ 123 public boolean canLaunch(Task taskToBeLaunched, 124 Collection<LocalizableMessage> incompatibilityReasons) 125 { 126 if (!isServerRunning() 127 && state == State.RUNNING 128 && runningOnSameServer(taskToBeLaunched)) 129 { 130 // All the operations are incompatible if they apply to this 131 // backend for safety. This is a short operation so the limitation 132 // has not a lot of impact. 133 Set<String> backends = new TreeSet<>(taskToBeLaunched.getBackends()); 134 backends.retainAll(getBackends()); 135 if (!backends.isEmpty()) 136 { 137 incompatibilityReasons.add(getIncompatibilityMessage(this, taskToBeLaunched)); 138 return false; 139 } 140 } 141 return true; 142 } 143 144 /** {@inheritDoc} */ 145 public boolean regenerateDescriptor() 146 { 147 return false; 148 } 149 150 /** {@inheritDoc} */ 151 public void runTask() 152 { 153 state = State.RUNNING; 154 lastException = null; 155 156 try 157 { 158 for (final DN groupDn : groupDns) 159 { 160 final Collection<ModificationItem> modifications = 161 getModifications(groupDn, dns); 162 if (!modifications.isEmpty()) 163 { 164 ModificationItem[] mods = 165 new ModificationItem[modifications.size()]; 166 modifications.toArray(mods); 167 168 SwingUtilities.invokeLater(new Runnable() 169 { 170 public void run() 171 { 172 printEquivalentCommandToModify(groupDn, modifications, false); 173 getProgressDialog().appendProgressHtml( 174 Utilities.getProgressWithPoints( 175 INFO_CTRL_PANEL_ADDING_TO_GROUP.get(groupDn), 176 ColorAndFontConstants.progressFont)); 177 } 178 }); 179 180 getInfo().getDirContext().modifyAttributes( 181 Utilities.getJNDIName(groupDn.toString()), mods); 182 183 SwingUtilities.invokeLater(new Runnable() 184 { 185 public void run() 186 { 187 getProgressDialog().appendProgressHtml( 188 Utilities.getProgressDone( 189 ColorAndFontConstants.progressFont)); 190 } 191 }); 192 } 193 } 194 state = State.FINISHED_SUCCESSFULLY; 195 } 196 catch (Throwable t) 197 { 198 lastException = t; 199 state = State.FINISHED_WITH_ERROR; 200 } 201 } 202 203 /** 204 * Returns the modifications that must be made to the provided group. 205 * @param groupDn the DN of the static group that must be updated. 206 * @param dns the list of entry DNs that must be added to the group. 207 * @return the list of modifications (in form of ModificationItem) that 208 * must be made to the provided group. 209 * @throws NamingException if an error occurs. 210 */ 211 private Collection<ModificationItem> getModifications(DN groupDn, 212 Set<DN> dns) throws NamingException 213 { 214 ArrayList<ModificationItem> modifications = new ArrayList<>(); 215 216 // Search for the group entry 217 SearchControls ctls = new SearchControls(); 218 ctls.setSearchScope(SearchControls.OBJECT_SCOPE); 219 ctls.setReturningAttributes( 220 new String[] { 221 ServerConstants.OBJECTCLASS_ATTRIBUTE_TYPE_NAME, 222 ServerConstants.ATTR_MEMBER, 223 ServerConstants.ATTR_UNIQUE_MEMBER 224 }); 225 String filter = BrowserController.ALL_OBJECTS_FILTER; 226 NamingEnumeration<SearchResult> result = 227 getInfo().getDirContext().search( 228 Utilities.getJNDIName(groupDn.toString()), 229 filter, ctls); 230 231 try 232 { 233 String memberAttr = ServerConstants.ATTR_MEMBER; 234 while (result.hasMore()) 235 { 236 SearchResult sr = result.next(); 237 Set<String> objectClasses = 238 ConnectionUtils.getValues(sr, ServerConstants 239 .OBJECTCLASS_ATTRIBUTE_TYPE_NAME); 240 if (objectClasses.contains(ServerConstants.OC_GROUP_OF_UNIQUE_NAMES)) 241 { 242 memberAttr = ServerConstants.ATTR_UNIQUE_MEMBER; 243 } 244 Set<String> values = ConnectionUtils.getValues(sr, memberAttr); 245 Set<String> dnsToAdd = new LinkedHashSet<>(); 246 if (values != null) 247 { 248 for (DN newDn : dns) 249 { 250 boolean found = false; 251 for (String dn : values) 252 { 253 if (Utilities.areDnsEqual(dn, newDn.toString())) 254 { 255 found = true; 256 break; 257 } 258 } 259 if (!found) 260 { 261 dnsToAdd.add(newDn.toString()); 262 } 263 } 264 } 265 else 266 { 267 for (DN newDn : dns) 268 { 269 dnsToAdd.add(newDn.toString()); 270 } 271 } 272 if (!dnsToAdd.isEmpty()) 273 { 274 Attribute attribute = new BasicAttribute(memberAttr); 275 for (String dn : dnsToAdd) 276 { 277 attribute.add(dn); 278 } 279 modifications.add(new ModificationItem( 280 DirContext.ADD_ATTRIBUTE, 281 attribute)); 282 } 283 } 284 } 285 finally 286 { 287 result.close(); 288 } 289 return modifications; 290 } 291} 292