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 2009-2010 Sun Microsystems, Inc. 015 * Portions Copyright 2014-2016 ForgeRock AS. 016 */ 017package org.opends.guitools.controlpanel.task; 018 019import static org.opends.messages.AdminToolMessages.*; 020import static org.opends.server.util.CollectionUtils.*; 021import static org.opends.server.util.SchemaUtils.*; 022 023import java.util.ArrayList; 024import java.util.Collection; 025import java.util.Collections; 026import java.util.HashSet; 027import java.util.LinkedHashSet; 028import java.util.List; 029import java.util.Map; 030import java.util.Set; 031 032import javax.swing.SwingUtilities; 033 034import org.forgerock.i18n.LocalizableMessage; 035import org.forgerock.opendj.ldap.schema.AttributeType; 036import org.forgerock.opendj.ldap.schema.ObjectClass; 037import org.forgerock.opendj.ldap.schema.SchemaBuilder; 038import org.opends.guitools.controlpanel.datamodel.ControlPanelInfo; 039import org.opends.guitools.controlpanel.datamodel.SomeSchemaElement; 040import org.opends.guitools.controlpanel.ui.ColorAndFontConstants; 041import org.opends.guitools.controlpanel.ui.ProgressDialog; 042import org.opends.guitools.controlpanel.util.Utilities; 043import org.opends.server.types.OpenDsException; 044import org.opends.server.types.Schema; 045 046/** 047 * The task that is in charge of modifying an attribute definition (and all 048 * the references to this attribute). 049 */ 050public class ModifyAttributeTask extends Task 051{ 052 private AttributeType oldAttribute; 053 private AttributeType newAttribute; 054 055 /** 056 * The constructor of the task. 057 * @param info the control panel info. 058 * @param dlg the progress dialog that shows the progress of the task. 059 * @param oldAttribute the old attribute definition. 060 * @param newAttribute the new attribute definition. 061 */ 062 public ModifyAttributeTask(ControlPanelInfo info, ProgressDialog dlg, 063 AttributeType oldAttribute, AttributeType newAttribute) 064 { 065 super(info, dlg); 066 if (oldAttribute == null) 067 { 068 throw new IllegalArgumentException("oldAttribute cannot be null."); 069 } 070 if (newAttribute == null) 071 { 072 throw new IllegalArgumentException("newAttribute cannot be null."); 073 } 074 this.oldAttribute = oldAttribute; 075 this.newAttribute = newAttribute; 076 } 077 078 @Override 079 public Type getType() 080 { 081 return Type.MODIFY_SCHEMA_ELEMENT; 082 } 083 084 @Override 085 public LocalizableMessage getTaskDescription() 086 { 087 return INFO_CTRL_PANEL_MODIFY_ATTRIBUTE_TASK_DESCRIPTION.get( 088 oldAttribute.getNameOrOID()); 089 } 090 091 @Override 092 public boolean canLaunch(Task taskToBeLaunched, 093 Collection<LocalizableMessage> incompatibilityReasons) 094 { 095 boolean canLaunch = true; 096 if (state == State.RUNNING && 097 (taskToBeLaunched.getType() == Task.Type.DELETE_SCHEMA_ELEMENT || 098 taskToBeLaunched.getType() == Task.Type.MODIFY_SCHEMA_ELEMENT || 099 taskToBeLaunched.getType() == Task.Type.NEW_SCHEMA_ELEMENT)) 100 { 101 incompatibilityReasons.add(getIncompatibilityMessage(this, 102 taskToBeLaunched)); 103 canLaunch = false; 104 } 105 return canLaunch; 106 } 107 108 @Override 109 public Set<String> getBackends() 110 { 111 return Collections.emptySet(); 112 } 113 114 @Override 115 protected List<String> getCommandLineArguments() 116 { 117 return Collections.emptyList(); 118 } 119 120 @Override 121 protected String getCommandLinePath() 122 { 123 return null; 124 } 125 126 @Override 127 public void runTask() 128 { 129 try 130 { 131 updateSchema(); 132 state = State.FINISHED_SUCCESSFULLY; 133 } 134 catch (Throwable t) 135 { 136 // TODO 137 //revertChanges(); 138 lastException = t; 139 state = State.FINISHED_WITH_ERROR; 140 } 141 } 142 143 private AttributeType getAttributeToAdd(AttributeType attrToDelete) 144 { 145 if (attrToDelete.equals(oldAttribute)) 146 { 147 return newAttribute; 148 } 149 else if (oldAttribute.equals(attrToDelete.getSuperiorType())) 150 { 151 // get a new attribute with the new superior type 152 return SomeSchemaElement.changeSuperiorType(attrToDelete, newAttribute); 153 } 154 else 155 { 156 // Nothing to be changed in the definition of the attribute itself. 157 return attrToDelete; 158 } 159 } 160 161 private ObjectClass getObjectClassToAdd(ObjectClass ocToDelete) 162 { 163 boolean containsAttribute = 164 ocToDelete.getRequiredAttributes().contains(oldAttribute) || 165 ocToDelete.getOptionalAttributes().contains(oldAttribute); 166 if (containsAttribute) 167 { 168 Map<String, List<String>> extraProperties = 169 DeleteSchemaElementsTask.cloneExtraProperties(ocToDelete); 170 Set<AttributeType> required = new HashSet<>(ocToDelete.getDeclaredRequiredAttributes()); 171 Set<AttributeType> optional = new HashSet<>(ocToDelete.getDeclaredOptionalAttributes()); 172 if (required.contains(oldAttribute)) 173 { 174 required.remove(oldAttribute); 175 required.add(newAttribute); 176 } 177 else if (optional.contains(oldAttribute)) 178 { 179 optional.remove(oldAttribute); 180 optional.add(newAttribute); 181 } 182 183 Schema schema = getInfo().getServerDescriptor().getSchema(); 184 String oid = ocToDelete.getOID(); 185 return new SchemaBuilder(schema.getSchemaNG()).buildObjectClass(oid) 186 .names(ocToDelete.getNames()) 187 .description(ocToDelete.getDescription()) 188 .superiorObjectClasses(getNameOrOIDsForOCs(ocToDelete.getSuperiorClasses())) 189 .requiredAttributes(getNameOrOIDsForATs(required)) 190 .optionalAttributes(getNameOrOIDsForATs(optional)) 191 .type(ocToDelete.getObjectClassType()) 192 .obsolete(ocToDelete.isObsolete()) 193 .extraProperties(extraProperties) 194 .addToSchema() 195 .toSchema() 196 .getObjectClass(oid); 197 } 198 else 199 { 200 // Nothing to be changed in the definition of the object class itself. 201 return ocToDelete; 202 } 203 } 204 205 /** 206 * Updates the schema. 207 * @throws OpenDsException if an error occurs. 208 */ 209 private void updateSchema() throws OpenDsException 210 { 211 Schema schema = getInfo().getServerDescriptor().getSchema(); 212 ArrayList<AttributeType> attrs = newArrayList(oldAttribute); 213 LinkedHashSet<AttributeType> attrsToDelete = 214 DeleteSchemaElementsTask.getOrderedAttributesToDelete(attrs, schema); 215 LinkedHashSet<ObjectClass> ocsToDelete = 216 DeleteSchemaElementsTask.getOrderedObjectClassesToDeleteFromAttrs( 217 attrsToDelete, schema); 218 219 LinkedHashSet<AttributeType> attrsToAdd = new LinkedHashSet<>(); 220 ArrayList<AttributeType> lAttrsToDelete = new ArrayList<>(attrsToDelete); 221 for (int i = lAttrsToDelete.size() - 1; i >= 0; i--) 222 { 223 AttributeType attrToAdd = getAttributeToAdd(lAttrsToDelete.get(i)); 224 if (attrToAdd != null) 225 { 226 attrsToAdd.add(attrToAdd); 227 } 228 } 229 230 ArrayList<ObjectClass> lOcsToDelete = new ArrayList<>(ocsToDelete); 231 LinkedHashSet<ObjectClass> ocsToAdd = new LinkedHashSet<>(); 232 for (int i = lOcsToDelete.size() - 1; i >= 0; i--) 233 { 234 ocsToAdd.add(getObjectClassToAdd(lOcsToDelete.get(i))); 235 } 236 237 SwingUtilities.invokeLater(new Runnable() 238 { 239 @Override 240 public void run() 241 { 242 getProgressDialog().appendProgressHtml(Utilities.applyFont( 243 INFO_CTRL_PANEL_EXPLANATION_TO_MODIFY_ATTRIBUTE.get( 244 oldAttribute.getNameOrOID())+"<br><br>", 245 ColorAndFontConstants.progressFont)); 246 } 247 }); 248 249 DeleteSchemaElementsTask deleteTask = 250 new DeleteSchemaElementsTask(getInfo(), getProgressDialog(), ocsToDelete, 251 attrsToDelete); 252 deleteTask.runTask(); 253 254 SwingUtilities.invokeLater(new Runnable() 255 { 256 @Override 257 public void run() 258 { 259 getProgressDialog().appendProgressHtml(Utilities.applyFont("<br><br>", 260 ColorAndFontConstants.progressFont)); 261 } 262 }); 263 264 NewSchemaElementsTask createTask = 265 new NewSchemaElementsTask(getInfo(), getProgressDialog(), ocsToAdd, 266 attrsToAdd); 267 createTask.runTask(); 268 269 notifyConfigurationElementCreated(newAttribute); 270 } 271}