/* * (c) Copyright 2010-2011 AgileBirds * * This file is part of OpenFlexo. * * OpenFlexo is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * OpenFlexo is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with OpenFlexo. If not, see <http://www.gnu.org/licenses/>. * */ package org.openflexo.foundation.wkf; import java.util.Enumeration; import java.util.Iterator; import java.util.Vector; import java.util.logging.Level; import java.util.logging.Logger; import org.openflexo.foundation.DeletableObject; import org.openflexo.foundation.validation.FixProposal; import org.openflexo.foundation.validation.ParameteredFixProposal; import org.openflexo.foundation.validation.Validable; import org.openflexo.foundation.validation.ValidationIssue; import org.openflexo.foundation.validation.ValidationRule; import org.openflexo.foundation.validation.ValidationWarning; import org.openflexo.foundation.wkf.dm.StatusInserted; import org.openflexo.foundation.wkf.dm.StatusRemoved; import org.openflexo.foundation.wkf.dm.WKFAttributeDataModification; import org.openflexo.foundation.xml.FlexoProcessBuilder; import org.openflexo.localization.FlexoLocalization; /** * Represents a list of status of a process * * @author sguerin * */ public final class StatusList extends WKFObject implements DeletableObject, LevelledObject { private static final Logger logger = Logger.getLogger(StatusList.class.getPackage().getName()); private Status _defaultStatus; private Vector<Status> _status; // ========================================================================== // ============================= Constructor ================================ // ========================================================================== /** * Constructor used during deserialization */ public StatusList(FlexoProcessBuilder builder) { this(builder.process); initializeDeserialization(builder); } /** * Default constructor */ private StatusList(FlexoProcess process) { super(process); _status = new Vector<Status>(); } /** * Default constructor (public API outside XML serialization) */ public StatusList(FlexoProcess process, boolean createDefaultStatus) { this(process); if (createDefaultStatus) { Status defaultStatus; try { defaultStatus = new Status(process, FlexoLocalization.localizedForKey("new")); defaultStatus.setDontGenerate(true); addToStatus(defaultStatus); setDefaultStatus(defaultStatus); } catch (DuplicateStatusException e) { // Should never happen ! e.printStackTrace(); } } } @Override public String getFullyQualifiedName() { return getProcess().getFullyQualifiedName() + ".STATUS_LIST"; } public Vector<Status> getStatus() { return _status; } public Vector<Status> getInheritedStatus() { Vector<Status> returned = new Vector<Status>(); FlexoProcess current = getProcess(); while (current.getParentProcess() != null) { current = current.getParentProcess(); if (current.getStatusList() != null) { returned.addAll(current.getStatusList().getStatus()); } } return returned; } public Vector<Status> getAllAvailableStatus() { Vector<Status> returned = new Vector<Status>(); returned.addAll(getStatus()); returned.addAll(getInheritedStatus()); return returned; } public void setStatus(Vector<Status> status) { _status = status; if (getProject() != null) { Iterator i = status.iterator(); while (i.hasNext()) { Status s = (Status) i.next(); getProject().getGlobalStatus().put(s.getFullyQualifiedName(), s); } } } public void addToStatus(Status aStatus) throws DuplicateStatusException { if (aStatus.getName() == null) { aStatus.setName(getNextNewStatusName()); } if (logger.isLoggable(Level.FINE)) { logger.fine("addToStatus with " + aStatus.getFullyQualifiedName()); } if (statusWithName(aStatus.getName()) != null) { if (isDeserializing()) { aStatus.setName(aStatus.getName() + "-1"); addToStatus(aStatus); return; } throw new DuplicateStatusException(aStatus, aStatus.getName()); } aStatus.setProcess(getProcess()); _status.add(aStatus); if (getProject() != null) { if (getProject().getGlobalStatus().get(aStatus.getFullyQualifiedName()) != null && getProject().getGlobalStatus().get(aStatus.getFullyQualifiedName()) != aStatus) { if (logger.isLoggable(Level.WARNING)) { logger.warning("There are two different statuses with the same name: " + aStatus.getFullyQualifiedName() + " this can be ignored during conversions"); } } getProject().getGlobalStatus().put(aStatus.getFullyQualifiedName(), aStatus); if (!isDeserializing()) { notifyStatusAdded(aStatus, getProcess()); } } else { if (logger.isLoggable(Level.WARNING)) { logger.warning("No project for status list " + this); } } } /** * @param status * @param process */ private void notifyStatusAdded(Status status, FlexoProcess process) { setChanged(); notifyObservers(new StatusInserted(status, process)); if (getProcess() != null && getProcess().getSubProcesses() != null) { for (Enumeration<FlexoProcess> e = getProcess().getSubProcesses().elements(); e.hasMoreElements();) { FlexoProcess subProcess = e.nextElement(); subProcess.getStatusList().notifyStatusAdded(status, process); } } if (getProcess() != null) { getProcess().notifyStatusListUpdated(); } setChanged(); notifyAttributeModification("allAvailableStatus", null, status); } public void removeFromStatus(Status aStatus) { _status.remove(aStatus); if (getProject() != null) { getProject().getGlobalStatus().remove(aStatus.getFullyQualifiedName()); } else if (logger.isLoggable(Level.WARNING)) { logger.warning("No project for status list " + this); } if (!aStatus.isDeleted()) { aStatus.delete(); } if (!isDeserializing()) { notifyStatusRemoved(aStatus, getProcess()); } } /** * @param status * @param process */ private void notifyStatusRemoved(Status status, FlexoProcess process) { setChanged(); notifyObservers(new StatusRemoved(status, process)); for (Enumeration e = getProcess().getSubProcesses().elements(); e.hasMoreElements();) { FlexoProcess subProcess = (FlexoProcess) e.nextElement(); subProcess.getStatusList().notifyStatusRemoved(status, process); } setChanged(); notifyAttributeModification("allAvailableStatus", null, status); } public Status statusWithName(String aStatusName) { if (getProject() != null) { if (aStatusName != null && aStatusName.indexOf(".STATUS.") > -1) { return getProject().getGlobalStatus().get(aStatusName); } } for (Enumeration e = _status.elements(); e.hasMoreElements();) { Status temp = (Status) e.nextElement(); if (temp != null && temp.getName().equals(aStatusName)) { return temp; } } return null; } public Status statusWithID(long aStatusId) { for (Enumeration e = _status.elements(); e.hasMoreElements();) { Status temp = (Status) e.nextElement(); if (temp.getFlexoID() == aStatusId) { return temp; } } return null; } private String defaultStatusAsString; public Status getDefaultStatus() { if (_defaultStatus == null && defaultStatusAsString != null) { if (getProject() != null) { _defaultStatus = getProject().getGlobalStatus().get(defaultStatusAsString); if (_defaultStatus == null && !isDeserializing()) { if (logger.isLoggable(Level.WARNING)) { logger.warning("Status with name " + defaultStatusAsString + " could not be found."); } defaultStatusAsString = null; } } else if (!isDeserializing()) { if (logger.isLoggable(Level.WARNING)) { logger.warning("No project for Status List in process " + (getProcess() != null ? getProcess().getName() : null)); } } } return _defaultStatus; } public void setDefaultStatus(Status defaultStatus) { Status old = this._defaultStatus; this._defaultStatus = defaultStatus; setChanged(); notifyObservers(new WKFAttributeDataModification("defaultStatus", old, defaultStatus)); } public String getDefaultStatusAsString() { if (getDefaultStatus() != null) { return getDefaultStatus().getFullyQualifiedName(); } else { return null; } } public void setDefaultStatusAsString(String status) { this.defaultStatusAsString = status; } public Status createNewStatus() { String newStatusName = getNextNewStatusName(); Status newStatus = null; try { newStatus = new Status(getProcess(), newStatusName); newStatus.setDescription(FlexoLocalization.localizedForKey("no_description")); addToStatus(newStatus); } catch (DuplicateStatusException e) { // should never happen e.printStackTrace(); } return newStatus; } public String getNextNewStatusName() { String baseName = "status"; String newStatusName = baseName; int inc = 0; while (statusWithName(newStatusName) != null) { inc++; newStatusName = baseName + inc; } return newStatusName; } public void deleteStatus(Status aStatus) { removeFromStatus(aStatus); } public boolean isStatusDeletable(Status aStatus) { return true; } /** * Return a Vector of all embedded WKFObjects * * @return a Vector of WKFObject instances */ @Override public Vector<WKFObject> getAllEmbeddedWKFObjects() { Vector<WKFObject> returned = new Vector<WKFObject>(); returned.add(this); returned.addAll(getStatus()); return returned; } /** * Returns the level of a StatusList (which is {@link FlexoLevel.PROCESS}). * * @see org.openflexo.foundation.wkf.LevelledObject#getLevel() */ @Override public FlexoLevel getLevel() { return FlexoLevel.PROCESS; } // ========================================================================== // ================================= Delete =============================== // ========================================================================== @Override public final void delete() { _status.removeAllElements(); super.delete(); deleteObservers(); } /** * Build and return a vector of all the objects that will be deleted during process deletion * * @param aVector * of DeletableObject */ @Override public Vector<WKFObject> getAllEmbeddedDeleted() { return getAllEmbeddedWKFObjects(); } // ========================================================================== // ============================= Validation ================================= // ========================================================================== public static class ProcessShouldHaveAtLeastAStatus extends ValidationRule { public ProcessShouldHaveAtLeastAStatus() { super(StatusList.class, "process_should_have_at_least_a_status"); } @Override public ValidationIssue applyValidation(final Validable object) { final StatusList statusList = (StatusList) object; if (statusList.getStatus().size() == 0) { ValidationWarning warning = new ValidationWarning(this, object, "process_($object.process.name)_has_no_status_defined"); warning.addToFixProposals(new CreateDefaultStatus()); return warning; } return null; } } public static class ProcessShouldHaveADefaultStatus extends ValidationRule { public ProcessShouldHaveADefaultStatus() { super(StatusList.class, "process_should_have_a_default_status"); } @Override public ValidationIssue applyValidation(final Validable object) { final StatusList statusList = (StatusList) object; if (statusList.getDefaultStatus() == null) { ValidationWarning warning = new ValidationWarning(this, object, "process_($object.process.name)_has_no_default_status"); for (Enumeration e = statusList.getStatus().elements(); e.hasMoreElements();) { Status status = (Status) e.nextElement(); warning.addToFixProposals(new SetDefaultStatus(status)); } return warning; } return null; } } public static class SetDefaultStatus extends FixProposal { public Status status; public SetDefaultStatus(Status aStatus) { super("set_default_status_for_process_($object.process.name)_to_($status.name)"); status = aStatus; } @Override protected void fixAction() { ((StatusList) getObject()).setDefaultStatus(status); } } public static class CreateDefaultStatus extends ParameteredFixProposal { public CreateDefaultStatus() { super("create_default_status_for_process_($object.process.name)", "defaultStatusName", "enter_a_name_for_the_default_status", FlexoLocalization.localizedForKey("new_status")); } @Override protected void fixAction() { Status newStatus = null; String newStatusName = (String) getValueForParameter("defaultStatusName"); StatusList statusList = (StatusList) getObject(); try { newStatus = new Status(statusList.getProcess(), newStatusName); newStatus.setDescription(FlexoLocalization.localizedForKey("no_description")); statusList.addToStatus(newStatus); } catch (DuplicateStatusException e) { newStatusName = statusList.getNextNewStatusName(); try { newStatus = new Status(statusList.getProcess(), newStatusName); newStatus.setDescription(FlexoLocalization.localizedForKey("no_description")); statusList.addToStatus(newStatus); } catch (DuplicateStatusException e1) { // should never happen e1.printStackTrace(); } } ((StatusList) getObject()).setDefaultStatus(newStatus); } } /** * Overrides getClassNameKey * * @see org.openflexo.foundation.FlexoModelObject#getClassNameKey() */ @Override public String getClassNameKey() { return "status_list"; } public int size() { return _status.size(); } public Enumeration<Status> elements() { return _status.elements(); } }