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 @Override 095 public Type getType() 096 { 097 return Type.NEW_ENTRY; 098 } 099 100 @Override 101 public Set<String> getBackends() 102 { 103 return backendSet; 104 } 105 106 @Override 107 public LocalizableMessage getTaskDescription() 108 { 109 return INFO_CTRL_PANEL_NEW_ENTRY_TASK_DESCRIPTION.get(dn); 110 } 111 112 @Override 113 protected String getCommandLinePath() 114 { 115 return null; 116 } 117 118 @Override 119 protected ArrayList<String> getCommandLineArguments() 120 { 121 return new ArrayList<>(); 122 } 123 124 @Override 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 @Override 147 public boolean regenerateDescriptor() 148 { 149 return false; 150 } 151 152 @Override 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().getConnection().getLdapContext(); 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 Set<ByteString> values = new LinkedHashSet<>(); 183 Iterator<ByteString> it = attr.iterator(); 184 while (it.hasNext()) 185 { 186 values.add(it.next()); 187 } 188 BasicAttribute a = new BasicAttribute(attr.getAttributeDescription().toString()); 189 for (ByteString value : values) 190 { 191 a.add(value.toByteArray()); 192 } 193 attrs.put(a); 194 } 195 196 SwingUtilities.invokeLater(new Runnable() 197 { 198 @Override 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 @Override 215 public void run() 216 { 217 getProgressDialog().appendProgressHtml( 218 Utilities.getProgressDone(ColorAndFontConstants.progressFont)); 219 boolean entryInserted = false; 220 if (parentNode != null) 221 { 222 boolean isReallyParentNode = false; 223 try 224 { 225 DN parentDN = DN.valueOf(parentNode.getDN()); 226 isReallyParentNode = 227 parentDN.equals(newEntry.getName().parent()); 228 } 229 catch (Throwable t) 230 { 231 // Bug 232 t.printStackTrace(); 233 isReallyParentNode = false; 234 } 235 if (isReallyParentNode) 236 { 237 insertNode(parentNode, newEntry.getName(), 238 isBaseDN(newEntry.getName())); 239 entryInserted = true; 240 } 241 } 242 if (!entryInserted) 243 { 244 BasicNode root = (BasicNode)controller.getTreeModel().getRoot(); 245 BasicNode realParentNode = findParentNode(newEntry.getName(), root); 246 if (realParentNode != null) 247 { 248 insertNode(realParentNode, newEntry.getName(), false); 249 } 250 else 251 { 252 if (isBaseDN(newEntry.getName())) 253 { 254 int nRootChildren = controller.getTreeModel().getChildCount( 255 controller.getTreeModel().getRoot()); 256 if (nRootChildren > 1) 257 { 258 // Insert in the root. 259 insertNode(root, newEntry.getName(), true); 260 } 261 } 262 } 263 } 264 } 265 }); 266 state = State.FINISHED_SUCCESSFULLY; 267 } 268 catch (Throwable t) 269 { 270 lastException = t; 271 state = State.FINISHED_WITH_ERROR; 272 } 273 } 274 275 /** Prints the equivalent command-line in the progress dialog. */ 276 private void printEquivalentCommand() 277 { 278 ArrayList<String> args = new ArrayList<>(getObfuscatedCommandLineArguments( 279 getConnectionCommandLineArguments(useAdminCtx, true))); 280 args.add(getNoPropertiesFileArgument()); 281 args.add("--defaultAdd"); 282 String equiv = getEquivalentCommandLine(getCommandLinePath("ldapmodify"), 283 args); 284 StringBuilder sb = new StringBuilder(); 285 sb.append(INFO_CTRL_PANEL_EQUIVALENT_CMD_TO_CREATE_ENTRY.get()).append("<br><b>"); 286 sb.append(equiv); 287 sb.append("<br>"); 288 String[] lines = ldif.split("\n"); 289 for (String line : lines) 290 { 291 sb.append(obfuscateLDIFLine(line)); 292 sb.append("<br>"); 293 } 294 sb.append("</b><br>"); 295 getProgressDialog().appendProgressHtml(Utilities.applyFont(sb.toString(), 296 ColorAndFontConstants.progressFont)); 297 } 298 299 private BasicNode findParentNode(DN dn, BasicNode root) 300 { 301 BasicNode parentNode = null; 302 int nRootChildren = controller.getTreeModel().getChildCount(root); 303 for (int i=0; i<nRootChildren; i++) 304 { 305 BasicNode node = 306 (BasicNode)controller.getTreeModel().getChild(root, i); 307 try 308 { 309 DN nodeDN = DN.valueOf(node.getDN()); 310 if (dn.isSubordinateOrEqualTo(nodeDN)) 311 { 312 if (dn.size() == nodeDN.size() + 1) 313 { 314 parentNode = node; 315 break; 316 } 317 else 318 { 319 parentNode = findParentNode(dn, node); 320 break; 321 } 322 } 323 } 324 catch (Throwable t) 325 { 326 // Bug 327 throw new RuntimeException("Unexpected error: "+t, t); 328 } 329 } 330 return parentNode; 331 } 332 333 private void insertNode(BasicNode parentNode, DN dn, boolean isSuffix) 334 { 335 TreePath parentPath = 336 new TreePath(controller.getTreeModel().getPathToRoot(parentNode)); 337 if (parentPath != null) 338 { 339 BrowserNodeInfo nodeInfo = 340 controller.getNodeInfoFromPath(parentPath); 341 if (nodeInfo != null) 342 { 343 TreePath newPath; 344 if (isSuffix) 345 { 346 newPath = controller.addSuffix(dn.toString(), parentNode.getDN()); 347 } 348 else 349 { 350 newPath = controller.notifyEntryAdded( 351 controller.getNodeInfoFromPath(parentPath), dn.toString()); 352 } 353 if (newPath != null) 354 { 355 controller.getTree().setSelectionPath(newPath); 356 controller.getTree().scrollPathToVisible(newPath); 357 } 358 } 359 } 360 } 361 362 private boolean isBaseDN(DN dn) 363 { 364 for (BackendDescriptor backend : getInfo().getServerDescriptor().getBackends()) 365 { 366 for (BaseDNDescriptor baseDN : backend.getBaseDns()) 367 { 368 if (baseDN.getDn().equals(dn)) 369 { 370 return true; 371 } 372 } 373 } 374 return false; 375 } 376}