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-2009 Sun Microsystems, Inc. 015 * Portions Copyright 2014-2016 ForgeRock AS. 016 */ 017package org.opends.guitools.controlpanel.task; 018 019import static org.opends.messages.AdminToolMessages.*; 020 021import java.util.ArrayList; 022import java.util.Collection; 023import java.util.HashSet; 024import java.util.Iterator; 025import java.util.LinkedHashSet; 026import java.util.Set; 027import java.util.TreeSet; 028 029import javax.naming.directory.BasicAttribute; 030import javax.naming.directory.BasicAttributes; 031import javax.naming.ldap.InitialLdapContext; 032import javax.swing.SwingUtilities; 033import javax.swing.tree.TreePath; 034 035import org.forgerock.i18n.LocalizableMessage; 036import org.forgerock.opendj.ldap.ByteString; 037import org.opends.guitools.controlpanel.browser.BrowserController; 038import org.opends.guitools.controlpanel.datamodel.BackendDescriptor; 039import org.opends.guitools.controlpanel.datamodel.BaseDNDescriptor; 040import org.opends.guitools.controlpanel.datamodel.ControlPanelInfo; 041import org.opends.guitools.controlpanel.ui.ColorAndFontConstants; 042import org.opends.guitools.controlpanel.ui.ProgressDialog; 043import org.opends.guitools.controlpanel.ui.nodes.BasicNode; 044import org.opends.guitools.controlpanel.ui.nodes.BrowserNodeInfo; 045import org.opends.guitools.controlpanel.util.Utilities; 046import org.opends.server.config.ConfigConstants; 047import org.forgerock.opendj.ldap.DN; 048import org.opends.server.types.Entry; 049 050/** The task launched when we must create an entry. */ 051public class NewEntryTask extends Task 052{ 053 private Entry newEntry; 054 private String ldif; 055 private Set<String> backendSet; 056 private BasicNode parentNode; 057 private BrowserController controller; 058 private DN dn; 059 private boolean useAdminCtx; 060 061 /** 062 * Constructor of the task. 063 * @param info the control panel information. 064 * @param dlg the progress dialog where the task progress will be displayed. 065 * @param newEntry the entry containing the new values. 066 * @param ldif the LDIF representation of the new entry. 067 * @param controller the BrowserController. 068 * @param parentNode the parent node in the tree of the entry that we want 069 * to create. 070 */ 071 public NewEntryTask(ControlPanelInfo info, ProgressDialog dlg, 072 Entry newEntry, String ldif, 073 BasicNode parentNode, BrowserController controller) 074 { 075 super(info, dlg); 076 backendSet = new HashSet<>(); 077 this.newEntry = newEntry; 078 this.ldif = ldif; 079 this.parentNode = parentNode; 080 this.controller = controller; 081 dn = newEntry.getName(); 082 for (BackendDescriptor backend : info.getServerDescriptor().getBackends()) 083 { 084 for (BaseDNDescriptor baseDN : backend.getBaseDns()) 085 { 086 if (dn.isSubordinateOrEqualTo(baseDN.getDn())) 087 { 088 backendSet.add(backend.getBackendID()); 089 } 090 } 091 } 092 } 093 094 /** {@inheritDoc} */ 095 public Type getType() 096 { 097 return Type.NEW_ENTRY; 098 } 099 100 /** {@inheritDoc} */ 101 public Set<String> getBackends() 102 { 103 return backendSet; 104 } 105 106 /** {@inheritDoc} */ 107 public LocalizableMessage getTaskDescription() 108 { 109 return INFO_CTRL_PANEL_NEW_ENTRY_TASK_DESCRIPTION.get(dn); 110 } 111 112 /** {@inheritDoc} */ 113 protected String getCommandLinePath() 114 { 115 return null; 116 } 117 118 /** {@inheritDoc} */ 119 protected ArrayList<String> getCommandLineArguments() 120 { 121 return new ArrayList<>(); 122 } 123 124 /** {@inheritDoc} */ 125 public boolean canLaunch(Task taskToBeLaunched, 126 Collection<LocalizableMessage> incompatibilityReasons) 127 { 128 if (!isServerRunning() 129 && state == State.RUNNING 130 && runningOnSameServer(taskToBeLaunched)) 131 { 132 // All the operations are incompatible if they apply to this 133 // backend for safety. This is a short operation so the limitation 134 // has not a lot of impact. 135 Set<String> backends = new TreeSet<>(taskToBeLaunched.getBackends()); 136 backends.retainAll(getBackends()); 137 if (!backends.isEmpty()) 138 { 139 incompatibilityReasons.add(getIncompatibilityMessage(this, taskToBeLaunched)); 140 return false; 141 } 142 } 143 return true; 144 } 145 146 /** {@inheritDoc} */ 147 public boolean regenerateDescriptor() 148 { 149 return false; 150 } 151 152 /** {@inheritDoc} */ 153 public void runTask() 154 { 155 state = State.RUNNING; 156 lastException = null; 157 158 try 159 { 160 InitialLdapContext ctx; 161 162 if (parentNode != null) 163 { 164 ctx = controller.findConnectionForDisplayedEntry(parentNode); 165 useAdminCtx = controller.isConfigurationNode(parentNode); 166 } 167 else 168 { 169 ctx = getInfo().getDirContext(); 170 useAdminCtx = true; 171 } 172 BasicAttributes attrs = new BasicAttributes(); 173 BasicAttribute objectclass = 174 new BasicAttribute(ConfigConstants.ATTR_OBJECTCLASS); 175 for (String oc : newEntry.getObjectClasses().values()) 176 { 177 objectclass.add(oc); 178 } 179 attrs.put(objectclass); 180 for (org.opends.server.types.Attribute attr : newEntry.getAttributes()) 181 { 182 String attrName = attr.getNameWithOptions(); 183 Set<ByteString> values = new LinkedHashSet<>(); 184 Iterator<ByteString> it = attr.iterator(); 185 while (it.hasNext()) 186 { 187 values.add(it.next()); 188 } 189 BasicAttribute a = new BasicAttribute(attrName); 190 for (ByteString value : values) 191 { 192 a.add(value.toByteArray()); 193 } 194 attrs.put(a); 195 } 196 197 SwingUtilities.invokeLater(new Runnable() 198 { 199 public void run() 200 { 201 printEquivalentCommand(); 202 getProgressDialog().appendProgressHtml( 203 Utilities.getProgressWithPoints( 204 INFO_CTRL_PANEL_CREATING_ENTRY.get(dn), 205 ColorAndFontConstants.progressFont)); 206 } 207 }); 208 209 ctx.createSubcontext(Utilities.getJNDIName(newEntry.getName().toString()), 210 attrs); 211 212 SwingUtilities.invokeLater(new Runnable() 213 { 214 public void run() 215 { 216 getProgressDialog().appendProgressHtml( 217 Utilities.getProgressDone(ColorAndFontConstants.progressFont)); 218 boolean entryInserted = false; 219 if (parentNode != null) 220 { 221 boolean isReallyParentNode = false; 222 try 223 { 224 DN parentDN = DN.valueOf(parentNode.getDN()); 225 isReallyParentNode = 226 parentDN.equals(newEntry.getName().parent()); 227 } 228 catch (Throwable t) 229 { 230 // Bug 231 t.printStackTrace(); 232 isReallyParentNode = false; 233 } 234 if (isReallyParentNode) 235 { 236 insertNode(parentNode, newEntry.getName(), 237 isBaseDN(newEntry.getName())); 238 entryInserted = true; 239 } 240 } 241 if (!entryInserted) 242 { 243 BasicNode root = (BasicNode)controller.getTreeModel().getRoot(); 244 BasicNode realParentNode = findParentNode(newEntry.getName(), root); 245 if (realParentNode != null) 246 { 247 insertNode(realParentNode, newEntry.getName(), false); 248 } 249 else 250 { 251 if (isBaseDN(newEntry.getName())) 252 { 253 int nRootChildren = controller.getTreeModel().getChildCount( 254 controller.getTreeModel().getRoot()); 255 if (nRootChildren > 1) 256 { 257 // Insert in the root. 258 insertNode(root, newEntry.getName(), true); 259 } 260 } 261 } 262 } 263 } 264 }); 265 state = State.FINISHED_SUCCESSFULLY; 266 } 267 catch (Throwable t) 268 { 269 lastException = t; 270 state = State.FINISHED_WITH_ERROR; 271 } 272 } 273 274 /** 275 * Prints the equivalent command-line in the progress dialog. 276 * 277 */ 278 private void printEquivalentCommand() 279 { 280 ArrayList<String> args = new ArrayList<>(getObfuscatedCommandLineArguments( 281 getConnectionCommandLineArguments(useAdminCtx, true))); 282 args.add(getNoPropertiesFileArgument()); 283 args.add("--defaultAdd"); 284 String equiv = getEquivalentCommandLine(getCommandLinePath("ldapmodify"), 285 args); 286 StringBuilder sb = new StringBuilder(); 287 sb.append(INFO_CTRL_PANEL_EQUIVALENT_CMD_TO_CREATE_ENTRY.get()).append("<br><b>"); 288 sb.append(equiv); 289 sb.append("<br>"); 290 String[] lines = ldif.split("\n"); 291 for (String line : lines) 292 { 293 sb.append(obfuscateLDIFLine(line)); 294 sb.append("<br>"); 295 } 296 sb.append("</b><br>"); 297 getProgressDialog().appendProgressHtml(Utilities.applyFont(sb.toString(), 298 ColorAndFontConstants.progressFont)); 299 } 300 301 private BasicNode findParentNode(DN dn, BasicNode root) 302 { 303 BasicNode parentNode = null; 304 int nRootChildren = controller.getTreeModel().getChildCount(root); 305 for (int i=0; i<nRootChildren; i++) 306 { 307 BasicNode node = 308 (BasicNode)controller.getTreeModel().getChild(root, i); 309 try 310 { 311 DN nodeDN = DN.valueOf(node.getDN()); 312 if (dn.isSubordinateOrEqualTo(nodeDN)) 313 { 314 if (dn.size() == nodeDN.size() + 1) 315 { 316 parentNode = node; 317 break; 318 } 319 else 320 { 321 parentNode = findParentNode(dn, node); 322 break; 323 } 324 } 325 } 326 catch (Throwable t) 327 { 328 // Bug 329 throw new RuntimeException("Unexpected error: "+t, t); 330 } 331 } 332 return parentNode; 333 } 334 335 private void insertNode(BasicNode parentNode, DN dn, boolean isSuffix) 336 { 337 TreePath parentPath = 338 new TreePath(controller.getTreeModel().getPathToRoot(parentNode)); 339 if (parentPath != null) 340 { 341 BrowserNodeInfo nodeInfo = 342 controller.getNodeInfoFromPath(parentPath); 343 if (nodeInfo != null) 344 { 345 TreePath newPath; 346 if (isSuffix) 347 { 348 newPath = controller.addSuffix(dn.toString(), parentNode.getDN()); 349 } 350 else 351 { 352 newPath = controller.notifyEntryAdded( 353 controller.getNodeInfoFromPath(parentPath), dn.toString()); 354 } 355 if (newPath != null) 356 { 357 controller.getTree().setSelectionPath(newPath); 358 controller.getTree().scrollPathToVisible(newPath); 359 } 360 } 361 } 362 } 363 364 private boolean isBaseDN(DN dn) 365 { 366 for (BackendDescriptor backend : getInfo().getServerDescriptor().getBackends()) 367 { 368 for (BaseDNDescriptor baseDN : backend.getBaseDns()) 369 { 370 if (baseDN.getDn().equals(dn)) 371 { 372 return true; 373 } 374 } 375 } 376 return false; 377 } 378}