// $Id: ResolvedCritic.java 14751 2008-05-16 16:02:55Z tfmorris $ // Copyright (c) 2002-2008 The Regents of the University of California. All // Rights Reserved. Permission to use, copy, modify, and distribute this // software and its documentation without fee, and without a written // agreement is hereby granted, provided that the above copyright notice // and this paragraph appear in all copies. This software program and // documentation are copyrighted by The Regents of the University of // California. The software program and documentation are supplied "AS // IS", without any accompanying services from The Regents. The Regents // does not warrant that the operation of the program will be // uninterrupted or error-free. The end-user understands that the program // was developed for research purposes and is advised not to rely // exclusively on the program for any reason. IN NO EVENT SHALL THE // UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT, // SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, INCLUDING LOST PROFITS, // ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF // THE UNIVERSITY OF CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF // SUCH DAMAGE. THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY // WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF // MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE // PROVIDED HEREUNDER IS ON AN "AS IS" BASIS, AND THE UNIVERSITY OF // CALIFORNIA HAS NO OBLIGATIONS TO PROVIDE MAINTENANCE, SUPPORT, // UPDATES, ENHANCEMENTS, OR MODIFICATIONS. package org.argouml.cognitive; import java.util.ArrayList; import java.util.List; import org.apache.log4j.Logger; import org.argouml.util.ItemUID; // TODO: Maybe the exception strings should be internationalized /** * This class is responsible for identifying one critic that has been resolved * by the user in one specific context. * * @author Michael Stockman */ public class ResolvedCritic { /** * The logger. */ private static final Logger LOG = Logger.getLogger(ResolvedCritic.class); /** * The name of the critic. */ private String critic; /** * The IDs of the objects that define the context of the critic. */ private List<String> offenders; /** * Create a new ResolvedCritic using the name of the Critic and the * List of objects that triggered the Critic given as parameters. * * @param cr The name of the Critic that has been resolved * @param offs The List of related objects. */ public ResolvedCritic(String cr, List<String> offs) { critic = cr; if (offs != null) { offenders = new ArrayList<String>(offs); } else { offenders = new ArrayList<String>(); } } /** * Same as {@link #ResolvedCritic(Critic,ListSet,boolean)}. * * @param c The Critic that has been resolved. * @param offs The set of objects that triggered the Critic. * @throws UnresolvableException If some of the objects does * not have a ItemUID and does not accept a new * one. */ public ResolvedCritic(Critic c, ListSet offs) throws UnresolvableException { this(c, offs, true); } /** * Creates a new ResolvedCritic from the given information. * * @param c The Critic that has been resolved. * @param offs The set of objects that triggered the Critic. * @param canCreate If it should try to assign new * ItemUIDs to objects that doesn't have. * @throws UnresolvableException If some of the objects does * not have a ItemUID and does not accept a new * one. */ public ResolvedCritic(Critic c, ListSet offs, boolean canCreate) throws UnresolvableException { if (c == null) { throw new IllegalArgumentException(); } //LOG.debug("Adding resolution for: " + c.getClass() + " " + canCreate); try { if (offs != null && offs.size() > 0) { offenders = new ArrayList<String>(offs.size()); importOffenders(offs, canCreate); } else { offenders = new ArrayList<String>(); } } catch (UnresolvableException ure) { try { getCriticString(c); } catch (UnresolvableException ure2) { throw new UnresolvableException(ure2.getMessage() + "\n" + ure.getMessage()); } throw ure; } critic = getCriticString(c); } /* * @see java.lang.Object#hashCode() * * This is a rather bad hash solution but with the {@link #equals(Object)} * defined as below, it is not possible to do better. */ @Override public int hashCode() { if (critic == null) { return 0; } return critic.hashCode(); } /** * equals returns true if and only if obj also is a ResolvedCritic, * has the same critic name, and has all related objects that this * object has. Note that it is not required that this object has all * related objects that that object has.<p> * * Formally that is inconsistent with {@link Object#equals(Object) * equals as specified in java.lang.Object}, * but it was probably practical somehow.<p> * * The param obj is the Object to compare to. * Returns true if equal according to the description, false * otherwise. * * {@inheritDoc} */ @Override public boolean equals(Object obj) { ResolvedCritic rc; if (obj == null || !(obj instanceof ResolvedCritic)) { return false; } rc = (ResolvedCritic) obj; if (critic == null) { if (rc.critic != null) { return false; } } else if (!critic.equals(rc.critic)) { return false; } if (offenders == null) { return true; } if (rc.offenders == null) { return false; } for (String offender : offenders) { if (offender == null) { continue; } int j; for (j = 0; j < rc.offenders.size(); j++) { if (offender.equals(rc.offenders.get(j))) { break; } } if (j >= rc.offenders.size()) { return false; } } return true; } /** * Obtains a String that identifies the type of Critic. * * @param c A Critic. * @throws UnresolvableException Not implemented. * @return A identifying name of the critic. */ protected String getCriticString(Critic c) throws UnresolvableException { // TODO: Should throw if the string is not good? if (c == null) { throw (new UnresolvableException("Critic is null")); } String s = c.getClass().toString(); return s; } /** * Imports the set of related objects in set to this object. If an * object does not have an ItemUID, canCreate determines if one will * be provided. If some object does not have an ItemUID and canCreate * is false or the object does not accept an ItemUID, then * UnresolvableException is thrown. * * @param set The set of related objects to import. * @param canCreate If ItemUIDs are allowed to be created. * @throws UnresolvableException if not all objects can be * imported. */ protected void importOffenders(ListSet set, boolean canCreate) throws UnresolvableException { String fail = null; for (Object obj : set) { String id = ItemUID.getIDOfObject(obj, canCreate); if (id == null) { if (!canCreate) { throw new UnresolvableException("ItemUID missing or " + "unable to " + "create for class: " + obj.getClass()); } if (fail == null) { fail = obj.getClass().toString(); } else { fail = fail + ", " + obj.getClass().toString(); } LOG.warn("Offender " + obj.getClass() + " unresolvable"); // Use this for fast fail instead. // Sacrificed for complete fail. d00mst //throw new UnresolvableException( // "Unable to create ItemUID for class: " // + obj.getClass()); } else { offenders.add(id); } } if (fail != null) { throw new UnresolvableException("Unable to create ItemUID for " + "some class(es): " + fail); } } /** * Gets the content of critic. * * @return The critic this instance resolves. */ public String getCritic() { return critic; } /** * Gets the list of related objects, offenders. * * @return The list of offenders of the critic this instance resolved. */ public List<String> getOffenderList() { return offenders; } /* * @see java.lang.Object#toString() */ @Override public String toString() { StringBuffer sb = new StringBuffer("ResolvedCritic: " + critic + " : "); for (int i = 0; i < offenders.size(); i++) { if (i > 0) { sb.append(", "); } sb.append(offenders.get(i)); } return sb.toString(); } }