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