/* Name: - Description: - Requires: - Provides: - Part of: ProcessPuzzle Framework, Domain and Business Model Ready Architecture. Provides content, workflow and social networking functionality. http://www.processpuzzle.com ProcessPuzzle - Content and Workflow Management Integration Business Platform Author(s): - Zsolt Zsuffa Copyright: (C) 2011 This program 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. This program 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 this program. If not, see <http://www.gnu.org/licenses/>. */ package com.processpuzzle.artifact_type.domain; import java.lang.reflect.Constructor; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.util.ArrayList; import java.util.Iterator; import java.util.List; import javax.xml.bind.annotation.XmlAttribute; import javax.xml.bind.annotation.XmlElement; import javax.xml.bind.annotation.XmlElementRef; import javax.xml.bind.annotation.XmlElementWrapper; import javax.xml.bind.annotation.XmlID; import javax.xml.bind.annotation.XmlIDREF; import javax.xml.bind.annotation.XmlRootElement; import com.processpuzzle.application.configuration.domain.RunTimeClassHierarchyAnalyser; import com.processpuzzle.application.security.domain.DefaultAccessRight; import com.processpuzzle.artifact.artifact.ArtifactList; import com.processpuzzle.artifact.domain.Artifact; import com.processpuzzle.artifact.domain.ArtifactFolder; import com.processpuzzle.artifact.domain.ArtifactListView; import com.processpuzzle.artifact.domain.ArtifactView; import com.processpuzzle.artifact_type_group.domain.ArtifactTypeGroup; import com.processpuzzle.business.definition.domain.SystemArtifact; import com.processpuzzle.fundamental_types.domain.GenericEntity; import com.processpuzzle.persistence.query.domain.DefaultIdentityExpression; import com.processpuzzle.persistence.query.domain.DefaultQueryContext; import com.processpuzzle.resource.resourcetype.domain.AssetType; import com.processpuzzle.resource.resourcetype.domain.ResourceType; import com.processpuzzle.util.domain.GeneralService; @XmlRootElement( name = "artifactType" ) public class ArtifactType extends GenericEntity<ArtifactType> implements AssetType { protected @XmlAttribute( required = true ) @XmlID String name; protected @XmlAttribute String artifactClassName; protected @XmlAttribute String domainClassName; protected @XmlAttribute String instanceFolder; protected @XmlElement( namespace="http://www.processpuzzle.com/GlobalElements" ) String description; protected @XmlElement String caption; protected @XmlElement String baseUri; protected @XmlAttribute boolean isSystem = false; protected @XmlAttribute( name = "createOnStartUp" ) boolean createOnStartup = false; protected @XmlAttribute boolean isSingleton = false; protected @XmlAttribute boolean pessimisticLock = false; protected @XmlAttribute boolean isVersionControlled = false; protected @XmlAttribute boolean refreshOnDocumentActivation = false; protected @XmlAttribute boolean refreshOnViewActivation = false; protected @XmlElementWrapper( name = "availableViews" ) @XmlElementRef List<ArtifactViewType> availableViews = new ArrayList<ArtifactViewType>(); private @XmlElementWrapper( name = "creationProperties" ) @XmlElement( name = "creationProperty" ) List<PropertyDefinition> propertyDefinitions = new ArrayList<PropertyDefinition>(); private @XmlElementWrapper( name = "defaultAccessRights" ) @XmlElement( name = "accessRight" ) List<DefaultAccessRight> defaultAccessRights = new ArrayList<DefaultAccessRight>(); private @XmlElementWrapper( name = "associatedMenuItems" ) @XmlElement( name = "menuItem" ) List<ArtifactMenu> associatedMenuItems = new ArrayList<ArtifactMenu>(); private @XmlIDREF @XmlAttribute( name = "group" ) ArtifactTypeGroup group; //Constructors ArtifactType( String typeName, ArtifactTypeGroup typeGroup, Class<? extends Artifact<?>> artifactClass ) { this.name = typeName ; this.group = typeGroup; this.artifactClassName = artifactClass != null ? artifactClass.getName() : null; } ArtifactType( String typeName, ArtifactTypeGroup typeGroup ) { this( typeName, typeGroup, null ); } protected ArtifactType() {} public ArtifactType( String typeName ) { this( typeName, null ); } // Public accessors and mutators public void addViewType( ArtifactViewType aView ) { this.availableViews.add( aView ); } public boolean canPlayRole( String what, String partyRoleTypeName ) { for( Iterator<DefaultAccessRight> iter = defaultAccessRights.iterator(); iter.hasNext(); ){ DefaultAccessRight defaultAccessRight = iter.next(); if( defaultAccessRight.getUserRoleName().equals( partyRoleTypeName ) ){ what.substring( 0, 1 ).toUpperCase(); Method method = null; try{ method = DefaultAccessRight.class.getDeclaredMethod( "isCan" + what, new Class[] {} ); }catch( SecurityException e ){ e.printStackTrace(); }catch( NoSuchMethodException e ){ e.printStackTrace(); } try{ return ((Boolean) method.invoke( defaultAccessRight, new Object[] {} )).booleanValue(); }catch( IllegalArgumentException e ){ e.printStackTrace(); }catch( IllegalAccessException e ){ e.printStackTrace(); }catch( InvocationTargetException e ){ e.printStackTrace(); } } } return false; } @Override public int compareTo( ResourceType o ) { return 0; } public DefaultAccessRight findAccessRightsFor( String partyRoleName ) { for( DefaultAccessRight anAccessRight : defaultAccessRights ){ if( anAccessRight.getUserRoleName().equals( partyRoleName ) ) return anAccessRight; } return null; } public ArtifactMenu findMenu( String name ) { for( ArtifactMenu menu : associatedMenuItems ){ if( menu.getName().equals( name ) ) return menu; } return null; } public PropertyDefinition findProperty( String propertyName ) { for( PropertyDefinition property : propertyDefinitions ){ if( property.getName().equals( propertyName ) ) return property; } return null; } public ArtifactViewType findView( String name ) { for( ArtifactViewType viewType : availableViews ){ if( viewType.getName().equals( name ) ) return viewType; } return null; } // todo: improve exception handling @SuppressWarnings("unchecked") public void instantiateViewsFor( Artifact<?> artifact ) { for( Iterator<ArtifactViewType> iter = availableViews.iterator(); iter.hasNext(); ){ ArtifactViewType aViewType = iter.next(); String viewClassName = aViewType.getViewClassName(); if( viewClassName != null && !viewClassName.equals( "" ) ){ String viewName = GeneralService.getLastToken( viewClassName, "." ); Class<? extends ArtifactView<?>> artifactViewClass = null; Class<? extends Artifact<?>> artifactClass = null; ArtifactView<?> artifactView = null; try{ artifactViewClass = (Class<? extends ArtifactView<?>>) Class.forName( viewClassName ); artifactClass = (Class<? extends Artifact<?>>) Class.forName( artifactClassName ); Class<?>[] argumentClasses = new Class[] { artifactClass, String.class, ArtifactViewType.class }; Object[] arguments = new Object[] { artifact, viewName, aViewType }; Constructor<?> viewConstructor = determineViewConstructor( artifactViewClass, argumentClasses ); artifactView = instantiateView( viewConstructor, argumentClasses, arguments ); }catch( ClassNotFoundException e ){ throw new ArtifactViewInstantiationException( artifact, viewClassName, e ); }catch( InstantiationException e ){ throw new ArtifactViewInstantiationException( artifact, viewClassName, e ); }catch( IllegalAccessException e ){ throw new ArtifactViewInstantiationException( artifact, viewClassName, e ); }catch( SecurityException e ){ throw new ArtifactViewInstantiationException( artifact, viewClassName, e ); }catch( IllegalArgumentException e ){ throw new ArtifactViewInstantiationException( artifact, viewClassName, e ); }catch( InvocationTargetException e ){ throw new ArtifactViewInstantiationException( artifact, viewClassName, e ); }catch( NoSuchMethodException e ){ throw new ArtifactViewInstantiationException( artifact, viewClassName, e ); } artifact.addView( viewName, artifactView ); } } } //Properties public String getArtifactClassName() { return artifactClassName; } public List<ArtifactViewType> getAvailableViews() { return availableViews; } public String getBaseUri() { return baseUri; } public String getCaption() { return caption; } public List<DefaultAccessRight> getDefaultAccessRights() { return defaultAccessRights; } public @Override @SuppressWarnings( "unchecked" ) <I extends DefaultIdentityExpression<ArtifactType>> I getDefaultIdentity() { defineIdentityExpressions(); return (I) defaultIdentity; } public DefaultAccessRight getDefaultRightByUserRole( String roleName ) { for( Iterator<DefaultAccessRight> iter = this.getDefaultAccessRights().iterator(); iter.hasNext(); ){ DefaultAccessRight defaultAccessRight = iter.next(); if( defaultAccessRight.getUserRoleName().equals( roleName ) ){ return defaultAccessRight; } } for( Iterator<DefaultAccessRight> iter = this.getGroup().getDefaultAccessRights().iterator(); iter.hasNext(); ){ DefaultAccessRight groupRight = iter.next(); if( groupRight.getUserRoleName().equals( roleName ) ){ return groupRight; } } return null; } public @Override String getDescription() { return description; } public String getDomainClassName() { return domainClassName; } public ArtifactTypeGroup getGroup() { return group; } @Override public String getName() { return name; } public String getInstanceFolderName() { if( instanceFolder == null ) instanceFolder = artifactClassName.substring( artifactClassName.lastIndexOf( "." ) +1 ) + "Instances"; return instanceFolder; } public String getInstanceFolderPath() { String path = SystemArtifact.ARTIFACTS_FOLDER.getPath(); path += ArtifactFolder.PATH_SEPARATOR + group.getName(); path += ArtifactFolder.PATH_SEPARATOR + getInstanceFolderName(); return path; } public List<PropertyDefinition> getPropertyDefinitions() { return propertyDefinitions; } public ArtifactViewType getViewType( String viewTypeName ) { for( Iterator<ArtifactViewType> iter = availableViews.iterator(); iter.hasNext(); ){ ArtifactViewType viewType = iter.next(); if( viewType.getName().equals( viewTypeName ) ) return viewType; } return null; } public boolean isCreateOnStartup() { return createOnStartup; } public boolean isSingleton() { return isSingleton; } public boolean isSystem() { return isSystem; } public boolean isVersionControlled() { return isVersionControlled; } public boolean isRefreshOnDocumentActivation() { return refreshOnDocumentActivation; } public boolean isRefreshOnViewActivation() { return refreshOnViewActivation; } public boolean isPessimisticLock() { return pessimisticLock; } public void setArtifactClassName( String artifactClassName ) { this.artifactClassName = artifactClassName; } public void setAvailableViews( List<ArtifactViewType> availableViews ) { this.availableViews = availableViews; } public void setBaseUri( String baseUri ) { this.baseUri = baseUri; } public void setCaption( String caption ) { this.caption = caption; } public void setCreateOnStartup( boolean createOnStartup ) { this.createOnStartup = createOnStartup; } public void setDefaultAccessRights( List<DefaultAccessRight> defaultAccessRights ) { this.defaultAccessRights = defaultAccessRights; } @Override public void setDescription( String description ) { this.description = description; } public void setDomainClassName( String domainClassName ) { this.domainClassName = domainClassName; } public void setGroup( ArtifactTypeGroup group ) { this.group = group; } public void setPessimisticLock( boolean pessimisticLock ) { this.pessimisticLock = pessimisticLock; } public void setPropertyDefinitions( List<PropertyDefinition> propertyDefinitions ) { this.propertyDefinitions = propertyDefinitions; } public void setSingleton( boolean isSingleton ) { this.isSingleton = isSingleton; } public void setSystem( boolean isSystem ) { this.isSystem = isSystem; } public void setVersionControlled( boolean isVersionControlled ) { this.isVersionControlled = isVersionControlled; } //Protected, private helper methods protected @Override void defineIdentityExpressions() { DefaultQueryContext context = new DefaultQueryContext(); defaultIdentity = new ArtifactTypeIdentity( this.name, context ); identities.add( defaultIdentity ); } private Constructor<?> determineViewConstructor( Class<? extends ArtifactView<?>> artifactViewClass, Class<?>[] argumentClasses ) throws NoSuchMethodException { Constructor<?> viewConstructor = null; try{ viewConstructor = artifactViewClass.getConstructor( argumentClasses ); }catch( SecurityException e ){ throw e; }catch( NoSuchMethodException e ){ RunTimeClassHierarchyAnalyser analyser = new RunTimeClassHierarchyAnalyser(); //Class<?>[] replacedClasses = null; boolean replaceHappened = false; if( analyser.checkIfIsChildOf( artifactViewClass, ArtifactListView.class ) ) replaceHappened = tryToReplaceSpecificArtifactWithMoreGenericArtifact( argumentClasses, ArtifactList.class ); else replaceHappened = tryToReplaceSpecificArtifactWithMoreGenericArtifact( argumentClasses, Artifact.class ); if( replaceHappened ) viewConstructor = determineViewConstructor( artifactViewClass, argumentClasses ); else throw e; } return viewConstructor; } private ArtifactView<?> instantiateView( Constructor<?> viewConstructor, Class<?>[] argumentClasses, Object[] arguments ) throws InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException { ArtifactView<?> artifactView = (ArtifactView<?>) viewConstructor.newInstance( arguments ); return artifactView; } private boolean tryToReplaceSpecificArtifactWithMoreGenericArtifact( Class<?>[] argumentClasses, @SuppressWarnings( "rawtypes" ) Class<? extends Artifact> artifactSubClass ) { boolean replaceHappened = false; RunTimeClassHierarchyAnalyser classHierarchyAnalyser = new RunTimeClassHierarchyAnalyser(); for( int i = 0; i < argumentClasses.length; i++ ){ if( classHierarchyAnalyser.checkIfIsChildOf( argumentClasses[i], artifactSubClass )) { argumentClasses[i] = artifactSubClass; replaceHappened = true; } } return replaceHappened; } }