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