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