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 2014-2015 ForgeRock AS 026 */ 027package org.opends.guitools.controlpanel.ui; 028 029import static org.opends.messages.AdminToolMessages.*; 030 031import java.io.IOException; 032import java.io.StringReader; 033import java.util.ArrayList; 034 035import javax.swing.SwingUtilities; 036 037import org.forgerock.i18n.LocalizableMessage; 038import org.opends.guitools.controlpanel.browser.BrowserController; 039import org.opends.guitools.controlpanel.event.ConfigurationChangeEvent; 040import org.opends.guitools.controlpanel.task.NewEntryTask; 041import org.opends.guitools.controlpanel.task.Task; 042import org.opends.guitools.controlpanel.ui.nodes.BasicNode; 043import org.opends.guitools.controlpanel.util.BackgroundTask; 044import org.opends.guitools.controlpanel.util.Utilities; 045import org.opends.server.types.Entry; 046import org.opends.server.types.LDIFImportConfig; 047import org.opends.server.util.LDIFException; 048import org.opends.server.util.LDIFReader; 049 050/** 051 * Abstract class used to re-factor some code among the different panels that 052 * are used to create a new entry. 053 */ 054public abstract class AbstractNewEntryPanel extends StatusGenericPanel 055{ 056 private static final long serialVersionUID = 6894546787832469213L; 057 058 /** The parent node that was selected when the user clicked on the new entry action. */ 059 protected BasicNode parentNode; 060 /** The browser controller. */ 061 protected BrowserController controller; 062 063 /** 064 * Sets the parent and the browser controller for this panel. 065 * @param parentNode the selected parent node (or <CODE>null</CODE> if no 066 * parent node was selected). 067 * @param controller the browser controller. 068 */ 069 public void setParent(BasicNode parentNode, BrowserController controller) 070 { 071 this.parentNode = parentNode; 072 this.controller = controller; 073 } 074 075 /** 076 * Returns the title for the progress dialog. 077 * @return the title for the progress dialog. 078 */ 079 protected abstract LocalizableMessage getProgressDialogTitle(); 080 /** 081 * Returns the LDIF representation of the new entry. 082 * @return the LDIF representation of the new entry. 083 */ 084 protected abstract String getLDIF(); 085 086 /** 087 * Updates the list of errors by checking the syntax of the entry. 088 * @param errors the list of errors that must be updated. 089 */ 090 protected abstract void checkSyntax(ArrayList<LocalizableMessage> errors); 091 092 /** 093 * Returns <CODE>true</CODE> if the syntax of the entry must be checked in 094 * the background and <CODE>false</CODE> otherwise. 095 * @return <CODE>true</CODE> if the syntax of the entry must be checked in 096 * the background and <CODE>false</CODE> otherwise. 097 */ 098 protected boolean checkSyntaxBackground() 099 { 100 return false; 101 } 102 103 /** {@inheritDoc} */ 104 public void okClicked() 105 { 106 final ArrayList<LocalizableMessage> errors = new ArrayList<>(); 107 108 if (checkSyntaxBackground()) 109 { 110 BackgroundTask<Void> worker = new BackgroundTask<Void>() 111 { 112 public Void processBackgroundTask() 113 { 114 try 115 { 116 Thread.sleep(2000); 117 } 118 catch (Throwable t) 119 { 120 } 121 checkSyntax(errors); 122 return null; 123 } 124 public void backgroundTaskCompleted(Void returnValue, Throwable t) 125 { 126 if (t != null) 127 { 128 errors.add(ERR_CTRL_PANEL_UNEXPECTED_DETAILS.get(t)); 129 } 130 displayMainPanel(); 131 setEnabledCancel(true); 132 setEnabledOK(true); 133 handleErrorsAndLaunchTask(errors); 134 } 135 }; 136 displayMessage(INFO_CTRL_PANEL_CHECKING_SUMMARY.get()); 137 setEnabledCancel(false); 138 setEnabledOK(false); 139 worker.startBackgroundTask(); 140 } 141 else 142 { 143 checkSyntax(errors); 144 handleErrorsAndLaunchTask(errors); 145 } 146 } 147 148 /** 149 * Checks that there are not errors in the list and launches a new entry 150 * task. 151 * @param errors the list of errors. 152 */ 153 private void handleErrorsAndLaunchTask(ArrayList<LocalizableMessage> errors) 154 { 155 Entry entry = null; 156 if (errors.isEmpty()) 157 { 158 try 159 { 160 entry = getEntry(); 161 } 162 catch (Throwable t) 163 { 164 // Unexpected error: getEntry() should work after calling checkSyntax 165 throw new RuntimeException("Unexpected error: "+t, t); 166 } 167 String dn = entry.getName().toString(); 168 // Checking for the existence of an entry is fast enough so we can do 169 // it on the event thread. 170 if (entryExists(dn)) 171 { 172 errors.add(ERR_CTRL_PANEL_ENTRY_ALREADY_EXISTS.get(dn)); 173 } 174 } 175 if (errors.isEmpty()) 176 { 177 final ProgressDialog dlg = new ProgressDialog( 178 Utilities.createFrame(), Utilities.getParentDialog(this), 179 getProgressDialogTitle(), getInfo()); 180 try 181 { 182 NewEntryTask newTask = 183 new NewEntryTask(getInfo(), dlg, entry, getLDIF(), 184 parentNode, controller); 185 for (Task task : getInfo().getTasks()) 186 { 187 task.canLaunch(newTask, errors); 188 } 189 if (errors.isEmpty()) 190 { 191 launchOperation(newTask, 192 INFO_CTRL_PANEL_CREATING_NEW_ENTRY_SUMMARY.get(), 193 INFO_CTRL_PANEL_CREATING_NEW_ENTRY_SUCCESSFUL_SUMMARY.get(), 194 INFO_CTRL_PANEL_CREATING_NEW_ENTRY_SUCCESSFUL_DETAILS.get(), 195 ERR_CTRL_PANEL_CREATING_NEW_ENTRY_ERROR_SUMMARY.get(), 196 ERR_CTRL_PANEL_CREATING_NEW_ENTRY_ERROR_DETAILS.get(), 197 null, 198 dlg); 199 dlg.setVisible(true); 200 Utilities.getParentDialog(this).setVisible(false); 201 SwingUtilities.invokeLater(new Runnable() 202 { 203 public void run() 204 { 205 dlg.toFront(); 206 } 207 }); 208 } 209 } 210 catch (Throwable t) 211 { 212 // Unexpected error: getEntry() should work after calling checkSyntax 213 throw new RuntimeException("Unexpected error: "+t, t); 214 } 215 } 216 if (!errors.isEmpty()) 217 { 218 displayErrorDialog(errors); 219 } 220 } 221 222 /** {@inheritDoc} */ 223 public void configurationChanged(ConfigurationChangeEvent ev) 224 { 225 updateErrorPaneIfServerRunningAndAuthRequired(ev.getNewDescriptor(), 226 INFO_CTRL_PANEL_NEW_ENTRY_REQUIRES_SERVER_RUNNING.get(), 227 INFO_CTRL_PANEL_NEW_ENTRY_REQUIRES_AUTHENTICATION.get()); 228 } 229 230 /** 231 * Returns the entry object representing what the user provided as data. 232 * @return the entry object representing what the user provided as data. 233 * @throws LDIFException if there is an error with the LDIF syntax. 234 * @throws IOException if there is an error creating the internal stream. 235 */ 236 protected Entry getEntry() throws LDIFException, IOException 237 { 238 LDIFImportConfig ldifImportConfig = null; 239 try 240 { 241 String ldif = getLDIF(); 242 if (ldif.trim().length() == 0) 243 { 244 throw new LDIFException(ERR_LDIF_REPRESENTATION_REQUIRED.get()); 245 } 246 247 ldifImportConfig = new LDIFImportConfig(new StringReader(ldif)); 248 LDIFReader reader = new LDIFReader(ldifImportConfig); 249 Entry entry = reader.readEntry(checkSchema()); 250 if (entry == null) 251 { 252 throw new LDIFException(ERR_LDIF_REPRESENTATION_REQUIRED.get()); 253 } 254 if (entry.getObjectClasses().isEmpty()) 255 { 256 throw new LDIFException(ERR_OBJECTCLASS_FOR_ENTRY_REQUIRED.get()); 257 } 258 return entry; 259 } 260 finally 261 { 262 if (ldifImportConfig != null) 263 { 264 ldifImportConfig.close(); 265 } 266 } 267 } 268 269 /** 270 * Returns <CODE>true</CODE> if the schema must be checked and 271 * <CODE>false</CODE> otherwise. 272 * @return <CODE>true</CODE> if the schema must be checked and 273 * <CODE>false</CODE> otherwise. 274 */ 275 protected boolean checkSchema() 276 { 277 return getInfo().getServerDescriptor().isSchemaEnabled(); 278 } 279}