package org.apache.maven.diagrams.connectors.classes;
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
import java.util.ArrayList;
import java.util.EnumSet;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import org.apache.maven.diagrams.connectors.classes.config.ClassesConnectorConfiguration;
import org.apache.maven.diagrams.connectors.classes.graph.ClassNode;
import org.apache.maven.diagrams.connectors.classes.model.ClassModel;
import org.apache.maven.diagrams.connectors.classes.model.FieldModel;
import org.apache.maven.diagrams.connectors.classes.model.MethodModel;
import org.apache.maven.diagrams.connectors.classes.model.ModifierModel;
import org.codehaus.plexus.logging.AbstractLogEnabled;
/**
* The class creates {@link ClassNode} objects for given class names. Translated objects are cached for feature asks.
*
* @author <a href="mailto:ptab@newitech.com">Piotr Tabor</a>
* @version $Id$
*/
public class DefaultClassNodesRepository extends AbstractLogEnabled implements ClassNodesRepository
{
private ClassModelsRepository classModels;
private Map<String, ClassNode> classNodes;
private ClassesConnectorConfiguration configuration;
public DefaultClassNodesRepository( ClassModelsRepository models, ClassesConnectorConfiguration a_configuration )
{
classModels = models;
classNodes = new HashMap<String, ClassNode>();
configuration = a_configuration;
}
/*
* (non-Javadoc)
*
* @see org.apache.maven.diagrams.connectors.classes.ClassNodesRepository#getClassNode(java.lang.String)
*/
public ClassNode getClassNode( String className ) throws ClassDataSourceException
{
ClassNode res = classNodes.get( className );
if ( res == null )
{
res = calculateClassNode( className );
classNodes.put( className, res );
}
return res;
}
/*
* (non-Javadoc)
*
* @see org.apache.maven.diagrams.connectors.classes.ClassNodesRepository#getMap()
*/
public Map<String, ClassNode> getMap()
{
return classNodes;
}
/**
* Does the real calculation of classNode from the className (fully qualified, dot separated)
*
* @param className
* @return
* @throws ClassDataSourceException
*/
protected ClassNode calculateClassNode( String className ) throws ClassDataSourceException
{
/* Calculate class model for the className */
ClassModel model = classModels.getClassModel( className );
ClassNode parent = null;
ClassNode result = new ClassNode();
/* Calculate (recursive) the classNode for the super class of the className (if needed for feature calculations) */
if ( ( model.getSuperClassName() != null )
&& ( configuration.getFullInheritancePaths()
|| configuration.getNodes().getPropagateInheritedFields() || configuration.getNodes().getPropagateInheritedMethods() ) )
{
parent = getClassNode( model.getSuperClassName() );
}
result.setClass_name( model.getClassifiedName() );
result.setSuperclassName( model.getSuperClassName() );
result.setInterface( model.isInterface() );
/*
* if propagateInheritedFields is on (and parent is available) copy not private fields from them to the current
* class)
*/
if ( ( parent != null ) && ( configuration.getNodes().getPropagateInheritedFields() ) )
{
copyNotPrivateFields( parent, result );
copyNotPrivateProperties( parent, result );
}
/*
* if propagateInheritedMethods is on (and parent is available) copy not private methods from them to the
* current class)
*/
if ( ( parent != null ) && ( configuration.getNodes().getPropagateInheritedMethods() ) )
copyNotPrivateMethods( parent, result );
result.setInterfaceNames( model.getInterfaces() );
copyMethodsFromModel( model, result );
copyFieldsFromModel( model, result );
if ( configuration.getNodes().getCompressJavaBeanProperties() )
compressProperties( result );
else
result.setProperties( new ArrayList<FieldModel>() );
return result;
}
/**
* Translates getters, setters and fields into single "property" object inside the given node;
*
* @param node -
* node to work on
*/
private void compressProperties( ClassNode node )
{
/* prepare list of possible properties (propertyName->type) */
HashMap<String, String> propertiesCandidates = new LinkedHashMap<String, String>();
for ( MethodModel method : node.getMethods() )
{
if ( method.isGetter() )
propertiesCandidates.put( method.getPropertyName(), method.getType() );
}
/* filter methods (we don't want getter's and setter's on methods list) */
List<MethodModel> newMethodsList = new ArrayList<MethodModel>();
for ( MethodModel method : node.getMethods() )
{
if ( !method.isGetter() && !method.isSetter() )
newMethodsList.add( method );
else if ( propertiesCandidates.get( method.getPropertyName() ) == null )
newMethodsList.add( method );
}
node.setMethods( newMethodsList );
/* filter fields */
List<FieldModel> newFieldsList = new ArrayList<FieldModel>();
for ( FieldModel field : node.getFields() )
{
if ( propertiesCandidates.get( field.getName() ) == null )
newFieldsList.add( field );
}
node.setFields( newFieldsList );
/* create properties list */
List<FieldModel> newPropertiesList = new ArrayList<FieldModel>();
for ( String fieldName : propertiesCandidates.keySet() )
{
FieldModel fm = new FieldModel();
fm.setName( fieldName );
fm.setModifiers( EnumSet.of( ModifierModel.PUBLIC ) );
fm.setType( propertiesCandidates.get( fieldName ) );
newPropertiesList.add( fm );
}
node.setProperties( newPropertiesList );
}
private void copyFieldsFromModel( ClassModel model, ClassNode result )
{
for ( FieldModel field : model.getFields() )
{
result.getFields().add( field );
}
}
private void copyMethodsFromModel( ClassModel model, ClassNode result )
{
for ( MethodModel method : model.getMethods() )
{
result.getMethods().add( method );
}
}
private void copyNotPrivateMethods( ClassNode from, ClassNode to )
{
for ( MethodModel method : from.getMethods() )
{
if ( !method.getModifiers().contains( ModifierModel.PRIVATE ) )
to.getMethods().add( method );
}
}
private void copyNotPrivateFields( ClassNode from, ClassNode to )
{
for ( FieldModel field : from.getFields() )
{
if ( !field.getModifiers().contains( ModifierModel.PRIVATE ) )
to.getFields().add( field );
}
}
private void copyNotPrivateProperties( ClassNode from, ClassNode to )
{
for ( FieldModel field : from.getProperties() )
{
if ( !field.getModifiers().contains( ModifierModel.PRIVATE ) )
to.getProperties().add( field );
}
}
}