All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.nakedobjects.metamodel.spec.JavaSpecification Maven / Gradle / Ivy

The newest version!
package org.nakedobjects.metamodel.spec;

import java.lang.reflect.Array;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.Hashtable;
import java.util.List;

import org.apache.log4j.Logger;
import org.nakedobjects.applib.Identifier;
import org.nakedobjects.metamodel.adapter.NakedObject;
import org.nakedobjects.metamodel.commons.debug.DebugInfo;
import org.nakedobjects.metamodel.commons.debug.DebugString;
import org.nakedobjects.metamodel.commons.exceptions.NakedObjectException;
import org.nakedobjects.metamodel.commons.exceptions.UnknownTypeException;
import org.nakedobjects.metamodel.commons.filters.AbstractFilter;
import org.nakedobjects.metamodel.commons.filters.Filter;
import org.nakedobjects.metamodel.commons.lang.ArrayUtils;
import org.nakedobjects.metamodel.commons.lang.CastUtils;
import org.nakedobjects.metamodel.commons.lang.JavaClassUtils;
import org.nakedobjects.metamodel.commons.lang.ToString;
import org.nakedobjects.metamodel.commons.names.NameConvertorUtils;
import org.nakedobjects.metamodel.exceptions.ReflectionException;
import org.nakedobjects.metamodel.facetdecorator.FacetDecoratorSet;
import org.nakedobjects.metamodel.facets.Facet;
import org.nakedobjects.metamodel.facets.FacetHolder;
import org.nakedobjects.metamodel.facets.naming.describedas.DescribedAsFacet;
import org.nakedobjects.metamodel.facets.naming.named.NamedFacet;
import org.nakedobjects.metamodel.facets.naming.named.NamedFacetInferred;
import org.nakedobjects.metamodel.facets.object.callbacks.CreatedCallbackFacet;
import org.nakedobjects.metamodel.facets.object.dirty.ClearDirtyObjectFacet;
import org.nakedobjects.metamodel.facets.object.dirty.IsDirtyObjectFacet;
import org.nakedobjects.metamodel.facets.object.dirty.MarkDirtyObjectFacet;
import org.nakedobjects.metamodel.facets.object.ident.icon.IconFacet;
import org.nakedobjects.metamodel.facets.object.ident.plural.PluralFacet;
import org.nakedobjects.metamodel.facets.object.ident.plural.PluralFacetInferred;
import org.nakedobjects.metamodel.facets.object.ident.title.TitleFacet;
import org.nakedobjects.metamodel.facets.object.notpersistable.InitiatedBy;
import org.nakedobjects.metamodel.facets.object.notpersistable.NotPersistableFacet;
import org.nakedobjects.metamodel.facets.ordering.OrderSet;
import org.nakedobjects.metamodel.java5.ImperativeFacet;
import org.nakedobjects.metamodel.java5.ImperativeFacetUtils;
import org.nakedobjects.metamodel.runtimecontext.ObjectInstantiationException;
import org.nakedobjects.metamodel.runtimecontext.RuntimeContext;
import org.nakedobjects.metamodel.runtimecontext.spec.IntrospectableSpecificationAbstract;
import org.nakedobjects.metamodel.runtimecontext.spec.feature.NakedObjectActionSet;
import org.nakedobjects.metamodel.spec.feature.NakedObjectAction;
import org.nakedobjects.metamodel.spec.feature.NakedObjectActionConstants;
import org.nakedobjects.metamodel.spec.feature.NakedObjectActionParameter;
import org.nakedobjects.metamodel.spec.feature.NakedObjectActionType;
import org.nakedobjects.metamodel.spec.feature.NakedObjectAssociation;
import org.nakedobjects.metamodel.spec.feature.NakedObjectMember;
import org.nakedobjects.metamodel.specloader.NakedObjectReflectorAbstract;
import org.nakedobjects.metamodel.specloader.SpecificationLoader;
import org.nakedobjects.metamodel.specloader.classsubstitutor.ClassSubstitutor;
import org.nakedobjects.metamodel.specloader.internal.NakedObjectActionImpl;
import org.nakedobjects.metamodel.specloader.internal.OneToManyAssociationImpl;
import org.nakedobjects.metamodel.specloader.internal.OneToOneAssociationImpl;
import org.nakedobjects.metamodel.specloader.internal.introspector.JavaIntrospector;
import org.nakedobjects.metamodel.specloader.internal.peer.JavaNakedObjectActionPeer;
import org.nakedobjects.metamodel.specloader.internal.peer.JavaNakedObjectAssociationPeer;
import org.nakedobjects.metamodel.specloader.internal.peer.NakedObjectAssociationPeer;
import org.nakedobjects.metamodel.util.CallbackUtils;
import org.nakedobjects.metamodel.util.SpecUtils;


public class JavaSpecification extends IntrospectableSpecificationAbstract implements DebugInfo, FacetHolder {

    private final static Logger LOG = Logger.getLogger(JavaSpecification.class);

    private class SubclassList {
        private final List classes = new ArrayList();

        public void addSubclass(final NakedObjectSpecification subclass) {
            classes.add(subclass);
        }

        public boolean hasSubclasses() {
            return !classes.isEmpty();
        }

        public NakedObjectSpecification[] toArray() {
            return classes.toArray(new NakedObjectSpecification[0]);
        }
    }

    private final SubclassList subclasses;
    private final NakedObjectReflectorAbstract reflector;

    private JavaIntrospector introspector;

    private Persistability persistable;

    private String pluralName;
    private String shortName;
    private String singularName;
    private String description;

    private NakedObjectSpecification[] interfaces;

    private IconFacet iconMethod;
    private MarkDirtyObjectFacet markDirtyObjectFacet;
    private ClearDirtyObjectFacet clearDirtyObjectFacet;
    private IsDirtyObjectFacet isDirtyObjectFacet;

    /**
     * Lazily built by {@link #getMember(Method)}.
     */
    private Hashtable membersByMethod = null;
    private Class cls;

    private boolean whetherAbstract;
    private boolean whetherFinal;
    private boolean service;

    
    // //////////////////////////////////////////////////////////////////////
    // Constructor
    // //////////////////////////////////////////////////////////////////////

    public JavaSpecification(
    		final Class cls, 
    		final NakedObjectReflectorAbstract reflector, 
    		final RuntimeContext runtimeContext) {
    	super(runtimeContext);
        this.introspector = new JavaIntrospector(cls, this, reflector);
        this.subclasses = new SubclassList();
        this.identifier = Identifier.classIdentifier(cls);
        this.reflector = reflector;
    }


    // //////////////////////////////////////////////////////////////////////
    // Class and stuff immediately derivable from class
    // //////////////////////////////////////////////////////////////////////

    @Override
    public void addSubclass(final NakedObjectSpecification subclass) {
        subclasses.addSubclass(subclass);
    }

    @Override
    public boolean hasSubclasses() {
        return subclasses.hasSubclasses();
    }

    @Override
    public NakedObjectSpecification[] interfaces() {
        return interfaces;
    }

    @Override
    public NakedObjectSpecification[] subclasses() {
        return subclasses.toArray();
    }

    // //////////////////////////////////////////////////////////////////////
    // Hierarchical
    // //////////////////////////////////////////////////////////////////////

    /**
     * Determines if this class represents the same class, or a subclass, of the specified class.
     */
    @Override
    public boolean isOfType(final NakedObjectSpecification specification) {
        if (specification == this) {
            return true;
        } else {
            if (interfaces != null) {
                for (int i = 0, len = interfaces.length; i < len; i++) {
                    if (interfaces[i].isOfType(specification)) {
                        return true;
                    }
                }
            }
            if (superClassSpecification != null) {
                return superClassSpecification.isOfType(specification);
            }
        }
        return false;
    }

    // //////////////////////////////////////////////////////////////////////
    // introspect
    // //////////////////////////////////////////////////////////////////////

    public synchronized void introspect(final FacetDecoratorSet decorator) {
        if (introspector == null) {
            throw new ReflectionException("Introspection already taken place, cannot introspect again");
        }

        cls = introspector.getIntrospectedClass();

        final boolean skipIntrospection = JavaClassUtils.isJavaClass(cls) || isValueClass(cls);
        if (skipIntrospection) {
        	if (LOG.isDebugEnabled()) {
        		LOG.debug("skipping introspection of properties and actions for " + cls.getName() + " (java.xxx class)");
        	}
        }

        introspector.introspectClass();

        fullName = introspector.getFullName();
        shortName = introspector.shortName();
        NamedFacet namedFacet = (NamedFacet) getFacet(NamedFacet.class);
        if (namedFacet == null) {
            namedFacet = new NamedFacetInferred(NameConvertorUtils.naturalName(shortName), this);
            addFacet(namedFacet);
        }

        PluralFacet pluralFacet = (PluralFacet) getFacet(PluralFacet.class);
        if (pluralFacet == null) {
            pluralFacet = new PluralFacetInferred(NameConvertorUtils.pluralName(namedFacet.value()), this);
            addFacet(pluralFacet);
        }

        whetherAbstract = introspector.isAbstract();
        whetherFinal = introspector.isFinal();

        final String superclassName = introspector.getSuperclass();
        final String[] interfaceNames = introspector.getInterfaces();

        if (skipIntrospection) {
            fields = new NakedObjectAssociation[0];
            objectActions = new NakedObjectAction[0];
            interfaces = new NakedObjectSpecification[0];
            
        } else {
            final SpecificationLoader loader = getReflector();
            if (superclassName != null) {
                superClassSpecification = loader.loadSpecification(superclassName);
                if (superClassSpecification != null) {
                	if (LOG.isDebugEnabled()) {
                		LOG.debug("  Superclass " + superclassName);
                	}
                    superClassSpecification.addSubclass(this);
                }
            }

            List interfaceSpecList = new ArrayList();
            for (int i = 0; i < interfaceNames.length; i++) {
                
                Class substitutedInterfaceClass = getSubstitutedClass(interfaceNames[i], getClassSubstitutor());
                if (substitutedInterfaceClass != null) {
                    NakedObjectSpecification interfacespec = loader.loadSpecification(substitutedInterfaceClass.getName());
                    interfaceSpecList.add(interfacespec);
                    interfacespec.addSubclass(this);
                }
            }
            interfaces = interfaceSpecList.toArray(new NakedObjectSpecification[]{});

            introspector.introspectPropertiesAndCollections();

            final OrderSet orderedFields = introspector.getFields();
            if (orderedFields != null) {
                fields = orderFields(orderedFields);
            }

            introspector.introspectActions();

            OrderSet orderedActions = introspector.getClassActions();

            orderedActions = introspector.getObjectActions();
            objectActions = orderActions(orderedActions);
        }

        decorateAllFacets(decorator);

        clearDirtyObjectFacet = (ClearDirtyObjectFacet) getFacet(ClearDirtyObjectFacet.class);
        markDirtyObjectFacet = (MarkDirtyObjectFacet) getFacet(MarkDirtyObjectFacet.class);
        isDirtyObjectFacet = (IsDirtyObjectFacet) getFacet(IsDirtyObjectFacet.class);
        namedFacet = (NamedFacet) getFacet(NamedFacet.class);
        singularName = namedFacet.value();

        pluralFacet = (PluralFacet) getFacet(PluralFacet.class);
        pluralName = pluralFacet.value();

        final DescribedAsFacet describedAsFacet = (DescribedAsFacet) getFacet(DescribedAsFacet.class);
        description = describedAsFacet.value();

        iconMethod = (IconFacet) getFacet(IconFacet.class);

        final NotPersistableFacet notPersistableFacet = (NotPersistableFacet) getFacet(NotPersistableFacet.class);
        final InitiatedBy initiatedBy = notPersistableFacet.value();
        if (initiatedBy == InitiatedBy.USER_OR_PROGRAM) {
            persistable = Persistability.TRANSIENT;
        } else if (initiatedBy == InitiatedBy.USER) {
            persistable = Persistability.PROGRAM_PERSISTABLE;
        } else {
            persistable = Persistability.USER_PERSISTABLE;
        }

        // indicates have now been introspected.
        introspector = null;
    }

    private boolean isValueClass(Class type) {
        return  type.getName().startsWith("org.nakedobjects.applib.value.");
    }


    /**
     * Looks up the class and runs it through the {@link #getClassSubstitutor()} obtained
     * from in the constructor.
     */
    private Class getSubstitutedClass(
    		final String fullyQualifiedClassName, 
    		final ClassSubstitutor classSubstitor) {
        Class interfaceClass;
        try {
            interfaceClass = Class.forName(fullyQualifiedClassName);
        } catch (ClassNotFoundException e) {
            return null;
        }
        return classSubstitor.getClass(interfaceClass);
    }


    /**
     * Added to try to track down a race condition. 
     */
    @Override
	public boolean isIntrospected() {
		return introspector == null;
	}



    // //////////////////////////////////////////////////////////////////////
    // Facets
    // //////////////////////////////////////////////////////////////////////

    private void decorateAllFacets(final FacetDecoratorSet decoratorSet) {
        decoratorSet.decorateAllFacets(this);
        for (int i = 0; i < fields.length; i++) {
            NakedObjectAssociation nakedObjectAssociation = fields[i];
			decoratorSet.decorateAllFacets(nakedObjectAssociation);
        }
        for (int i = 0; i < objectActions.length; i++) {
            NakedObjectAction nakedObjectAction = objectActions[i];
			decoratorSet.decorateAllFacets(nakedObjectAction);
            final NakedObjectActionParameter[] parameters = objectActions[i].getParameters();
            for (int j = 0; j < parameters.length; j++) {
                decoratorSet.decorateAllFacets(parameters[j]);
            }
        }
    }

    // //////////////////////////////////////////////////////////////////////
    // getMember, catalog...
    // //////////////////////////////////////////////////////////////////////

    public NakedObjectMember getMember(final Method method) {
        if (membersByMethod == null) {
            membersByMethod = new Hashtable();
            cataloguePropertiesAndCollections(membersByMethod);
            catalogueActions(membersByMethod);
        }
        return membersByMethod.get(method);
    }

    private void cataloguePropertiesAndCollections(final Hashtable membersByMethod) {
        Filter noop = AbstractFilter.noop(NakedObjectAssociation.class);
        final NakedObjectAssociation[] fields = getAssociations(noop);
        for (int i = 0; i < fields.length; i++) {
            final NakedObjectAssociation field = fields[i];
            final Facet[] facets = field.getFacets(ImperativeFacet.FILTER);
            for (int j = 0; j < facets.length; j++) {
                final ImperativeFacet facet = ImperativeFacetUtils.getImperativeFacet(facets[j]);
                for(Method imperativeFacetMethod: facet.getMethods()) {
                	membersByMethod.put(imperativeFacetMethod, field);
                }
            }
        }
    }

    private void catalogueActions(final Hashtable membersByMethod) {
        final NakedObjectAction[] userActions = getObjectActions(NakedObjectActionConstants.USER);
        for (int i = 0; i < userActions.length; i++) {
            final NakedObjectAction userAction = userActions[i];
            final Facet[] facets = userAction.getFacets(ImperativeFacet.FILTER);
            for (int j = 0; j < facets.length; j++) {
                final ImperativeFacet facet = ImperativeFacetUtils.getImperativeFacet(facets[j]);
                for(Method imperativeFacetMethod: facet.getMethods()) {
                	membersByMethod.put(imperativeFacetMethod, userAction);
                }
            }
        }
    }

    // //////////////////////////////////////////////////////////////////////
    // getStaticallyAvailableFields, getDynamically..Fields, getField
    // //////////////////////////////////////////////////////////////////////

    public NakedObjectAssociation getAssociation(final String id) {
        // TODO put fields into hash
        for (int i = 0; i < fields.length; i++) {
            if (fields[i].getId().equals(id)) {
                return fields[i];
            }
        }
        throw new NakedObjectSpecificationException("No field called '" + id + "' in '" + getSingularName() + "'");
    }

    // //////////////////////////////////////////////////////////////////////
    // getObjectAction, getAction, getActions, getClassActions
    // //////////////////////////////////////////////////////////////////////

    public NakedObjectAction getObjectAction(
            final NakedObjectActionType type,
            final String id,
            final NakedObjectSpecification[] parameters) {
        final NakedObjectAction[] availableActions = ArrayUtils.combine(objectActions, getServiceActions(type));
        return getAction(availableActions, type, id, parameters);
    }

    public NakedObjectAction getObjectAction(final NakedObjectActionType type, final String nameParmsIdentityString) {
        final NakedObjectAction[] availableActions = ArrayUtils.combine(objectActions, getServiceActions(type));
        return getAction2(availableActions, type, nameParmsIdentityString);
    }

    private NakedObjectAction getAction(
            final NakedObjectAction[] availableActions,
            final NakedObjectActionType type,
            final String actionName,
            final NakedObjectSpecification[] parameters) {
        outer: for (int i = 0; i < availableActions.length; i++) {
            final NakedObjectAction action = availableActions[i];
            if (action.getActions().length > 0) {
                // deal with action set
                final NakedObjectAction a = getAction(action.getActions(), type, actionName, parameters);
                if (a != null) {
                    return a;
                }
            } else {
                // regular action
                if (!action.getType().equals(type)) {
                    continue outer;
                }
                if (actionName != null && !actionName.equals(action.getId())) {
                    continue outer;
                }
                if (action.getParameters().length != parameters.length) {
                    continue outer;
                }
                for (int j = 0; j < parameters.length; j++) {
                    if (!parameters[j].isOfType(action.getParameters()[j].getSpecification())) {
                        continue outer;
                    }
                }
                return action;
            }
        }
        return null;
    }

    private NakedObjectAction getAction2(
            final NakedObjectAction[] availableActions,
            final NakedObjectActionType type,
            final String nameParmsIdentityString) {
        if (nameParmsIdentityString == null) {
            return null;
        }
        outer: for (int i = 0; i < availableActions.length; i++) {
            final NakedObjectAction action = availableActions[i];
            if (action.getActions().length > 0) {
                // deal with action set
                final NakedObjectAction a = getAction2(action.getActions(), type, nameParmsIdentityString);
                if (a != null) {
                    return a;
                }
            } else {
                // regular action
                if (!sameActionTypeOrNotSpecified(type, action)) {
                    continue outer;
                }
                if (!nameParmsIdentityString.equals(action.getIdentifier().toNameParmsIdentityString())) {
                    continue outer;
                }
                return action;
            }
        }
        return null;
    }

    @Override
    protected NakedObjectAction[] getActions(final NakedObjectAction[] availableActions, final NakedObjectActionType type) {
        final List actions = new ArrayList();
        for (final NakedObjectAction action : availableActions) {
            final NakedObjectActionType actionType = action.getType();
            if (actionType == NakedObjectActionConstants.SET) {
                final NakedObjectActionSet actionSet = (NakedObjectActionSet) action;
                final NakedObjectAction[] subActions = actionSet.getActions();
                for (final NakedObjectAction subAction : subActions) {
                    if (sameActionTypeOrNotSpecified(type, subAction)) {
                        actions.add(subAction);
                        break;
                    }
                }
            } else {
                if (sameActionTypeOrNotSpecified(type, action)) {
                    actions.add(action);
                }
            }
        }

        return actions.toArray(new NakedObjectAction[0]);
    }

    private boolean sameActionTypeOrNotSpecified(final NakedObjectActionType type, final NakedObjectAction action) {
        return type == null || action.getType().equals(type);
    }

    // //////////////////////////////////////////////////////////////////////
    // orderFields, orderActions
    // //////////////////////////////////////////////////////////////////////

    private NakedObjectAssociation[] orderFields(final OrderSet order) {
        final NakedObjectAssociation[] fields = new NakedObjectAssociation[order.size()];
        final Enumeration elements = CastUtils.enumerationOver(order.elements(),
                NakedObjectAssociation.class);
        int actionCnt = 0;
        while (elements.hasMoreElements()) {
            final Object element = elements.nextElement();
            if (element instanceof JavaNakedObjectAssociationPeer) {
                final JavaNakedObjectAssociationPeer javaNakedObjectAssociationPeer = (JavaNakedObjectAssociationPeer) element;
                final NakedObjectAssociation nakedObjectAssociation = createNakedObjectField(javaNakedObjectAssociationPeer);
                fields[actionCnt++] = nakedObjectAssociation;
            } else if (element instanceof OrderSet) {
                // Not supported at present
            } else {
                throw new UnknownTypeException(element);
            }
        }

        if (actionCnt < fields.length) {
            final NakedObjectAssociation[] actualActions = new NakedObjectAssociation[actionCnt];
            System.arraycopy(fields, 0, actualActions, 0, actionCnt);
            return actualActions;
        }
        return fields;
    }

    private NakedObjectAction[] orderActions(final OrderSet order) {
        final NakedObjectAction[] actions = new NakedObjectAction[order.size()];
        final Enumeration elements = CastUtils.enumerationOver(order.elements(), NakedObjectAction.class);
        int actionCnt = 0;
        while (elements.hasMoreElements()) {
            final Object element = elements.nextElement();
            if (element instanceof JavaNakedObjectActionPeer) {
                final JavaNakedObjectActionPeer javaNakedObjectActionPeer = (JavaNakedObjectActionPeer) element;
                final String actionId = javaNakedObjectActionPeer.getIdentifier().getMemberName();
                final NakedObjectAction nakedObjectAction = new NakedObjectActionImpl(actionId, javaNakedObjectActionPeer, getRuntimeContext());
                actions[actionCnt++] = nakedObjectAction;
            } else if (element instanceof OrderSet) {
                final OrderSet set = ((OrderSet) element);
                actions[actionCnt++] = new NakedObjectActionSet("", set.getGroupFullName(), orderActions(set), getRuntimeContext());
            } else {
                throw new UnknownTypeException(element);
            }
        }

        if (actionCnt < actions.length) {
            final NakedObjectAction[] actualActions = new NakedObjectAction[actionCnt];
            System.arraycopy(actions, 0, actualActions, 0, actionCnt);
            return actualActions;
        }
        return actions;
    }

    private NakedObjectAssociation createNakedObjectField(final NakedObjectAssociationPeer peer) {
        NakedObjectAssociation field;
        if (peer.isOneToOne()) {
            field = new OneToOneAssociationImpl(peer, getRuntimeContext());

        } else if (peer.isOneToMany()) {
            field = new OneToManyAssociationImpl(peer, getRuntimeContext());

        } else {
            throw new NakedObjectException();
        }
        return field;
    }

    @Override
    public boolean isCollectionOrIsAggregated() {
        return isCollection() || isValueOrIsAggregated();
    }

    @Override
    public boolean isAbstract() {
        return whetherAbstract;
    }

    @Override
    public boolean isFinal() {
        return whetherFinal;
    }

    @Override
    public boolean isService() {
        return service;
    }

    public String getShortName() {
        return shortName;
    }

    public String getSingularName() {
        return singularName;
    }

    public String getPluralName() {
        return pluralName;
    }

    public String getDescription() {
        return description == null ? "" : description;
    }

    private TitleFacet titleFacet;

    public String getTitle(final NakedObject object) {
        if (titleFacet == null) {
            titleFacet = (TitleFacet) getFacet(TitleFacet.class);
        }
        if (titleFacet != null) {
            final String titleString = titleFacet.title(object);
            if (titleString != null && !titleString.equals("")) {
                return titleString;
            }
        }
        return (this.isService() ? "" : "Untitled ") + getSingularName();
    }

    @Override
    public String getIconName(final NakedObject reference) {
        if (iconMethod == null) {
            return null;
        } else {
            return iconMethod.iconName(reference);
        }
    }

    @Override
    public Persistability persistability() {
        return persistable;
    }

    // //////////////////////////////////////////////////////////////////////
    // createObject
    // //////////////////////////////////////////////////////////////////////

    @Override
    public Object createObject(CreationMode creationMode) {
        if (cls.isArray()) {
            return Array.newInstance(cls.getComponentType(), 0);
        }
        
        try {
            Object object = getRuntimeContext().instantiate(cls);
            
            if (creationMode == CreationMode.INITIALIZE) {
                final NakedObject adapter = getRuntimeContext().adapterFor(object);
                
                // initialize new object
                final NakedObjectAssociation[] fields = adapter.getSpecification().getAssociations();
        		for (int i = 0; i < fields.length; i++) {
        		    fields[i].toDefault(adapter);
        		}
        		getRuntimeContext().injectDependenciesInto(object);
        		
        		CallbackUtils.callCallback(adapter, CreatedCallbackFacet.class);
            }
			return object;
        } catch (final ObjectInstantiationException e) {
            throw new NakedObjectException("Failed to create instance of type " + cls.getName(), e);
        }
    }

    @Override
    public boolean isDirty(final NakedObject object) {
        return isDirtyObjectFacet == null ? false : isDirtyObjectFacet.invoke(object);
    }

    @Override
    public void clearDirty(final NakedObject object) {
        if (clearDirtyObjectFacet != null) {
            clearDirtyObjectFacet.invoke(object);
        }
    }

    @Override
    public void markDirty(final NakedObject object) {
        if (markDirtyObjectFacet != null) {
            markDirtyObjectFacet.invoke(object);
        }
    }

    // //////////////////////////////////////////////////////////////////////
    // markAsService
    // //////////////////////////////////////////////////////////////////////

    /**
     * TODO: should ensure that service has at least one user action; fix when specification knows of its
     * hidden methods.
     * 
     * 
     * if (objectActions != null && objectActions.length == 0) {
     *     throw new NakedObjectSpecificationException("Service object " + getFullName() + " should have at least one user action");
     * }
     * 
*/ public void markAsService() { final NakedObjectAssociation[] fields = getAssociations(); if (fields != null && fields.length > 0) { String fieldNames = ""; for (int i = 0; i < fields.length; i++) { final String name = fields[i].getId(); if ("id".indexOf(name) == -1) { fieldNames += (fieldNames.length() > 0 ? ", " : "") + name; } } if (fieldNames.length() > 0) { throw new NakedObjectSpecificationException("Service object " + getFullName() + " should have no fields, but has: " + fieldNames); } } service = true; } // ////////////////////////////////////////////////////////////////////// // Debug, toString // ////////////////////////////////////////////////////////////////////// public void debugData(final DebugString debug) { debug.blankLine(); debug.appendln("Title", getFacet(TitleFacet.class)); if (iconMethod != null) { debug.appendln("Icon", iconMethod); } debug.unindent(); } public String debugTitle() { return "NO Member Specification"; } @Override public String toString() { final ToString str = new ToString(this); str.append("class", fullName); str.append("type", SpecUtils.typeNameFor(this)); str.append("persistable", persistable); str.append("superclass", superClassSpecification == null ? "Object" : superClassSpecification.getFullName()); return str.toString(); } // ////////////////////////////////////////////////////////////////// // Dependencies (from constructor) // ////////////////////////////////////////////////////////////////// private NakedObjectReflectorAbstract getReflector() { return reflector; } /** * Derived from {@link #getReflector()} */ private ClassSubstitutor getClassSubstitutor() { return reflector.getClassSubstitutor(); } } // Copyright (c) Naked Objects Group Ltd.




© 2015 - 2024 Weber Informatics LLC | Privacy Policy