Package org.apache.maven.plugin.doap

Source Code of org.apache.maven.plugin.doap.DoapUtil$ReflectionValueExtractor

package org.apache.maven.plugin.doap;

/*
* 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.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Method;
import java.net.MalformedURLException;
import java.net.SocketTimeoutException;
import java.net.URL;
import java.text.DateFormat;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Date;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.StringTokenizer;
import java.util.WeakHashMap;
import java.util.Map.Entry;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.Set;
import java.util.Properties;

import org.apache.commons.httpclient.Credentials;
import org.apache.commons.httpclient.HttpClient;
import org.apache.commons.httpclient.HttpStatus;
import org.apache.commons.httpclient.MultiThreadedHttpConnectionManager;
import org.apache.commons.httpclient.UsernamePasswordCredentials;
import org.apache.commons.httpclient.auth.AuthScope;
import org.apache.commons.httpclient.methods.GetMethod;
import org.apache.commons.httpclient.params.HttpClientParams;
import org.apache.commons.httpclient.params.HttpMethodParams;
import org.apache.maven.model.Contributor;
import org.apache.maven.project.MavenProject;
import org.apache.maven.settings.Proxy;
import org.apache.maven.settings.Settings;
import org.apache.maven.wagon.proxy.ProxyInfo;
import org.apache.maven.wagon.proxy.ProxyUtils;
import org.codehaus.plexus.i18n.I18N;
import org.codehaus.plexus.interpolation.EnvarBasedValueSource;
import org.codehaus.plexus.interpolation.InterpolationException;
import org.codehaus.plexus.interpolation.ObjectBasedValueSource;
import org.codehaus.plexus.interpolation.PrefixedObjectValueSource;
import org.codehaus.plexus.interpolation.PropertiesBasedValueSource;
import org.codehaus.plexus.interpolation.RegexBasedInterpolator;
import org.codehaus.plexus.util.IOUtil;
import org.codehaus.plexus.util.StringUtils;
import org.codehaus.plexus.util.introspection.ClassMap;
import org.codehaus.plexus.util.xml.XMLWriter;
import org.codehaus.plexus.util.xml.XmlWriterUtil;

import com.hp.hpl.jena.rdf.model.Model;
import com.hp.hpl.jena.rdf.model.ModelFactory;
import com.hp.hpl.jena.rdf.model.RDFReader;
import com.hp.hpl.jena.rdf.model.impl.RDFDefaultErrorHandler;

/**
* Utility class for {@link DoapMojo} class.
*
* @author <a href="mailto:vincent.siveton@gmail.com">Vincent Siveton</a>
* @version $Id: DoapUtil.java 1057614 2011-01-11 13:28:29Z vsiveton $
* @since 1.0
*/
public class DoapUtil
{
    /** Email regex */
    private static final String EMAIL_REGEX =
        "^[_A-Za-z0-9-]+(\\.[_A-Za-z0-9-]+)*@[A-Za-z0-9]+(\\.[A-Za-z0-9]+)*(\\.[A-Za-z]{2,})$";

    /** Email pattern */
    private static final Pattern EMAIL_PATTERN = Pattern.compile( EMAIL_REGEX );

    /** Magic number to repeat '=' */
    private static final int REPEAT_EQUALS = 21;

    /** The default timeout used when fetching url, i.e. 2000. */
    public static final int DEFAULT_TIMEOUT = 2000;

    /** RDF resource attribute */
    protected static final String RDF_RESOURCE = "rdf:resource";

    /** RDF nodeID attribute */
    protected static final String RDF_NODE_ID = "rdf:nodeID";

    /** DoaP Organizations stored by name */
    private static Map<String, DoapUtil.Organization> organizations = new HashMap<String, DoapUtil.Organization>();

    /**
     * Write comments in the DOAP file header
     *
     * @param writer not null
     */
    public static void writeHeader( XMLWriter writer )
    {
        XmlWriterUtil.writeLineBreak( writer );

        XmlWriterUtil.writeCommentLineBreak( writer );
        XmlWriterUtil.writeComment( writer, StringUtils.repeat( "=", REPEAT_EQUALS ) + " - DO NOT EDIT THIS FILE! - "
            + StringUtils.repeat( "=", REPEAT_EQUALS ) );
        XmlWriterUtil.writeCommentLineBreak( writer );
        XmlWriterUtil.writeComment( writer, " " );
        XmlWriterUtil.writeComment( writer, "Any modifications will be overwritten." );
        XmlWriterUtil.writeComment( writer, " " );
        DateFormat dateFormat = DateFormat.getDateTimeInstance( DateFormat.SHORT, DateFormat.SHORT, Locale.US );
        XmlWriterUtil.writeComment( writer, "Generated by Maven Doap Plugin " + getPluginVersion() + " on "
            + dateFormat.format( new Date( System.currentTimeMillis() ) ) );
        XmlWriterUtil.writeComment( writer, "See: http://maven.apache.org/plugins/maven-doap-plugin/" );
        XmlWriterUtil.writeComment( writer, " " );
        XmlWriterUtil.writeCommentLineBreak( writer );

        XmlWriterUtil.writeLineBreak( writer );
    }

    /**
     * Write comment.
     *
     * @param writer not null
     * @param comment not null
     * @throws IllegalArgumentException if comment is null or empty
     * @since 1.1
     */
    public static void writeComment( XMLWriter writer, String comment )
        throws IllegalArgumentException
    {
        if ( StringUtils.isEmpty( comment ) )
        {
            throw new IllegalArgumentException( "comment should be defined" );
        }

        XmlWriterUtil.writeLineBreak( writer );
        XmlWriterUtil.writeCommentText( writer, comment, 2 );
    }

    /**
     * @param writer not null
     * @param xmlnsPrefix could be null
     * @param name not null
     * @param value could be null. In this case, the element is not written.
     * @throws IllegalArgumentException if name is null or empty
     */
    public static void writeElement( XMLWriter writer, String xmlnsPrefix, String name, String value )
        throws IllegalArgumentException
    {
        if ( StringUtils.isEmpty( name ) )
        {
            throw new IllegalArgumentException( "name should be defined" );
        }

        if ( value != null )
        {
            writeStartElement( writer, xmlnsPrefix, name );
            writer.writeText( value );
            writer.endElement();
        }
    }

    /**
     * @param writer not null
     * @param xmlnsPrefix could be null
     * @param name not null
     * @param lang not null
     * @param value could be null. In this case, the element is not written.
     * @throws IllegalArgumentException if name is null or empty
     */
    public static void writeElement( XMLWriter writer, String xmlnsPrefix, String name, String value, String lang )
        throws IllegalArgumentException
    {
        if ( StringUtils.isEmpty( lang ) )
        {
            writeElement( writer, xmlnsPrefix, name, value );
            return;
        }

        if ( StringUtils.isEmpty( name ) )
        {
            throw new IllegalArgumentException( "name should be defined" );
        }

        if ( value != null )
        {
            writeStartElement( writer, xmlnsPrefix, name );
            writer.addAttribute( "xml:lang", lang );
            writer.writeText( value );
            writer.endElement();
        }
    }

    /**
     * @param writer not null
     * @param xmlnsPrefix could be null
     * @param name not null
     * @throws IllegalArgumentException if name is null or empty
     * @since 1.1
     */
    public static void writeStartElement( XMLWriter writer, String xmlnsPrefix, String name )
        throws IllegalArgumentException
    {
        if ( StringUtils.isEmpty( name ) )
        {
            throw new IllegalArgumentException( "name should be defined" );
        }

        if ( StringUtils.isNotEmpty( xmlnsPrefix ) )
        {
            writer.startElement( xmlnsPrefix + ":" + name );
        }
        else
        {
            writer.startElement( name );
        }
    }

    /**
     * @param writer not null
     * @param xmlnsPrefix could be null
     * @param name not null
     * @param value could be null. In this case, the element is not written.
     * @throws IllegalArgumentException if name is null or empty
     */
    public static void writeRdfResourceElement( XMLWriter writer, String xmlnsPrefix, String name, String value )
        throws IllegalArgumentException
    {
        if ( StringUtils.isEmpty( name ) )
        {
            throw new IllegalArgumentException( "name should be defined" );
        }

        if ( value != null )
        {
            writeStartElement( writer, xmlnsPrefix, name );
            writer.addAttribute( RDF_RESOURCE, value );
            writer.endElement();
        }
    }

    /**
     * @param writer not null
     * @param name not null
     * @param value could be null. In this case, the element is not written.
     * @throws IllegalArgumentException if name is null or empty
     */
    public static void writeRdfNodeIdElement( XMLWriter writer, String xmlnsPrefix, String name, String value )
        throws IllegalArgumentException
    {
        if ( StringUtils.isEmpty( name ) )
        {
            throw new IllegalArgumentException( "name should be defined" );
        }

        if ( value != null )
        {
            writeStartElement( writer, xmlnsPrefix, name );
            writer.addAttribute( RDF_NODE_ID, value );
            writer.endElement();
        }
    }

    /**
     * @param i18n the internationalization component
     * @param developersOrContributors list of <code>{@link Contributor}</code>
     * @return a none null list of <code>{@link Contributor}</code> which have a <code>developer</code> DOAP role.
     */
    public static List<Contributor> getContributorsWithDeveloperRole( I18N i18n,
                                                                      List<Contributor> developersOrContributors )
    {
        return filterContributorsByDoapRoles( i18n, developersOrContributors ).get( "developers" );
    }

    /**
     * @param i18n the internationalization component
     * @param developersOrContributors list of <code>{@link Contributor}</code>
     * @return a none null list of <code>{@link Contributor}</code> which have a <code>documenter</code> DOAP role.
     */
    public static List<Contributor> getContributorsWithDocumenterRole( I18N i18n,
                                                                       List<Contributor> developersOrContributors )
    {
        return filterContributorsByDoapRoles( i18n, developersOrContributors ).get( "documenters" );
    }

    /**
     * @param i18n the internationalization component
     * @param developersOrContributors list of <code>{@link Contributor}</code>
     * @return a none null list of <code>{@link Contributor}</code> which have an <code>helper</code> DOAP role.
     */
    public static List<Contributor> getContributorsWithHelperRole( I18N i18n, List<Contributor> developersOrContributors )
    {
        return filterContributorsByDoapRoles( i18n, developersOrContributors ).get( "helpers" );
    }

    /**
     * @param i18n the internationalization component
     * @param developersOrContributors list of <code>{@link Contributor}</code>
     * @return a none null list of <code>{@link Contributor}</code> which have a <code>maintainer</code> DOAP role.
     */
    public static List<Contributor> getContributorsWithMaintainerRole( I18N i18n,
                                                                       List<Contributor> developersOrContributors )
    {
        return filterContributorsByDoapRoles( i18n, developersOrContributors ).get( "maintainers" );
    }

    /**
     * @param i18n the internationalization component
     * @param developersOrContributors list of <code>{@link Contributor}</code>
     * @return a none null list of <code>{@link Contributor}</code> which have a <code>tester</code> DOAP role.
     */
    public static List<Contributor> getContributorsWithTesterRole( I18N i18n, List<Contributor> developersOrContributors )
    {
        return filterContributorsByDoapRoles( i18n, developersOrContributors ).get( "testers" );
    }

    /**
     * @param i18n the internationalization component
     * @param developersOrContributors list of <code>{@link Contributor}</code>
     * @return a none null list of <code>{@link Contributor}</code> which have a <code>translator</code> DOAP role.
     */
    public static List<Contributor> getContributorsWithTranslatorRole( I18N i18n,
                                                                       List<Contributor> developersOrContributors )
    {
        return filterContributorsByDoapRoles( i18n, developersOrContributors ).get( "translators" );
    }

    /**
     * @param i18n the internationalization component
     * @param developersOrContributors list of <code>{@link Contributor}</code>
     * @return a none null list of <code>{@link Contributor}</code> which have an <code>unknown</code> DOAP role.
     */
    public static List<Contributor> getContributorsWithUnknownRole( I18N i18n,
                                                                    List<Contributor> developersOrContributors )
    {
        return filterContributorsByDoapRoles( i18n, developersOrContributors ).get( "unknowns" );
    }

    /**
     * Utility class for keeping track of DOAP organizations in the DoaP mojo.
     *
     * @author <a href="mailto:t.fliss@gmail.com">Tim Fliss</a>
     * @version $Id: DoapUtil.java 1057614 2011-01-11 13:28:29Z vsiveton $
     * @since 1.1
     */
    public static class Organization
    {
        private String name;

        private String url;

        private List<String> members = new LinkedList<String>();

        public Organization( String name, String url )
        {
            this.name = name;
            this.url = url;
        }

        public void setName( String name )
        {
            this.name = name;
        }

        public String getName()
        {
            return name;
        }

        public void setUrl( String url )
        {
            this.url = url;
        }

        public String getUrl()
        {
            return url;
        }

        public void addMember( String nodeId )
        {
            members.add( nodeId );
        }

        public List<String> getMembers()
        {
            return members;
        }
    }

    /**
     * put an organization from the pom file in the organization list.
     *
     * @param name from the pom file (e.g. Yoyodyne)
     * @param url from the pom file (e.g. http://yoyodyne.example.org/about)
     * @return the existing organization if a duplicate, or a new one.
     */
    public static DoapUtil.Organization addOrganization( String name, String url )
    {
        Organization organization = organizations.get( name );

        if ( organization == null )
        {
            organization = new DoapUtil.Organization( name, url );
        }

        organizations.put( name, organization );

        return organization;
    }

    // unique RDF blank node index scoped internal to the DOAP file
    private static int nodeNumber = 1;

    /**
     * get a unique (within the DoaP file) RDF blank node ID
     *
     * @return the nodeID
     * @see <a href="http://www.w3.org/TR/rdf-syntax-grammar/#section-Syntax-blank-nodes">
     *      http://www.w3.org/TR/rdf-syntax-grammar/#section-Syntax-blank-nodes</a>
     */
    public static String getNodeId()
    {
        return "b" + nodeNumber++;
    }

    /**
     * get the set of Organizations that people are members of
     *
     * @return Map.EntrySet of DoapUtil.Organization
     */
    public static Set<Entry<String, DoapUtil.Organization>> getOrganizations()
    {
        return organizations.entrySet();
    }

    /**
     * Validate the given DOAP file.
     *
     * @param doapFile not null and should exists.
     * @return an empty list if the DOAP file is valid, otherwise a list of errors.
     * @since 1.1
     */
    public static List<String> validate( File doapFile )
    {
        if ( doapFile == null || !doapFile.isFile() )
        {
            throw new IllegalArgumentException( "The DOAP file should exist" );
        }

        Model model = ModelFactory.createDefaultModel();
        RDFReader r = model.getReader( "RDF/XML" );
        r.setProperty( "error-mode", "strict-error" );
        final List<String> errors = new ArrayList<String>();
        r.setErrorHandler( new RDFDefaultErrorHandler()
        {
            @Override
            public void error( Exception e )
            {
                errors.add( e.getMessage() );
            }
        } );

        try
        {
            r.read( model, doapFile.toURI().toURL().toString() );
        }
        catch ( MalformedURLException e )
        {
            // ignored
        }

        return errors;
    }

    /**
     * @param str not null
     * @return <code>true</code> if the str parameter is a valid email, <code>false</code> otherwise.
     * @since 1.1
     */
    public static boolean isValidEmail( String str )
    {
        if ( StringUtils.isEmpty( str ) )
        {
            return false;
        }

        Matcher matcher = EMAIL_PATTERN.matcher( str );
        return matcher.matches();
    }

    /**
     * Fetch an URL
     *
     * @param settings the user settings used to fetch the url with an active proxy, if defined.
     * @param url the url to fetch
     * @throws IOException if any
     * @see #DEFAULT_TIMEOUT
     * @since 1.1
     */
    public static void fetchURL( Settings settings, URL url )
        throws IOException
    {
        if ( url == null )
        {
            throw new IllegalArgumentException( "The url is null" );
        }

        if ( "file".equals( url.getProtocol() ) )
        {
            InputStream in = null;
            try
            {
                in = url.openStream();
            }
            finally
            {
                IOUtil.close( in );
            }

            return;
        }

        // http, https...
        HttpClient httpClient = new HttpClient( new MultiThreadedHttpConnectionManager() );
        httpClient.getHttpConnectionManager().getParams().setConnectionTimeout( DEFAULT_TIMEOUT );
        httpClient.getHttpConnectionManager().getParams().setSoTimeout( DEFAULT_TIMEOUT );
        httpClient.getParams().setBooleanParameter( HttpClientParams.ALLOW_CIRCULAR_REDIRECTS, true );

        // Some web servers don't allow the default user-agent sent by httpClient
        httpClient.getParams().setParameter( HttpMethodParams.USER_AGENT,
                                             "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0)" );

        if ( settings != null && settings.getActiveProxy() != null )
        {
            Proxy activeProxy = settings.getActiveProxy();

            ProxyInfo proxyInfo = new ProxyInfo();
            proxyInfo.setNonProxyHosts( activeProxy.getNonProxyHosts() );

            if ( StringUtils.isNotEmpty( activeProxy.getHost() )
                && !ProxyUtils.validateNonProxyHosts( proxyInfo, url.getHost() ) )
            {
                httpClient.getHostConfiguration().setProxy( activeProxy.getHost(), activeProxy.getPort() );

                if ( StringUtils.isNotEmpty( activeProxy.getUsername() ) && activeProxy.getPassword() != null )
                {
                    Credentials credentials =
                        new UsernamePasswordCredentials( activeProxy.getUsername(), activeProxy.getPassword() );

                    httpClient.getState().setProxyCredentials( AuthScope.ANY, credentials );
                }
            }
        }

        GetMethod getMethod = new GetMethod( url.toString() );
        try
        {
            int status;
            try
            {
                status = httpClient.executeMethod( getMethod );
            }
            catch ( SocketTimeoutException e )
            {
                // could be a sporadic failure, one more retry before we give up
                status = httpClient.executeMethod( getMethod );
            }

            if ( status != HttpStatus.SC_OK )
            {
                throw new FileNotFoundException( url.toString() );
            }
        }
        finally
        {
            getMethod.releaseConnection();
        }
    }

    /**
     * Interpolate a string with project and settings.
     *
     * @param value could be null
     * @param project not null
     * @param settings could be null
     * @return the value trimmed and interpolated or null if the interpolation doesn't work.
     * @since 1.1
     */
    public static String interpolate( String value, final MavenProject project, Settings settings )
    {
        if ( project == null )
        {
            throw new IllegalArgumentException( "project is required" );
        }

        if ( value == null )
        {
            return value;
        }

        if ( !value.contains( "${" ) )
        {
            return value.trim();
        }

        RegexBasedInterpolator interpolator = new RegexBasedInterpolator();
        try
        {
            interpolator.addValueSource( new EnvarBasedValueSource() );
        }
        catch ( IOException e )
        {
        }
        interpolator.addValueSource( new PropertiesBasedValueSource( System.getProperties() ) );
        interpolator.addValueSource( new PropertiesBasedValueSource( project.getProperties() ) );
        interpolator.addValueSource( new PrefixedObjectValueSource( "project", project ) );
        interpolator.addValueSource( new PrefixedObjectValueSource( "pom", project ) );
        interpolator.addValueSource( new ObjectBasedValueSource( project )
        {
            @Override
            public Object getValue( String expression )
            {
                try
                {
                    return ReflectionValueExtractor.evaluate( expression, project, true );
                }
                catch ( Exception e )
                {
                    addFeedback( "Failed to extract \'" + expression + "\' from: " + project, e );
                }

                return null;
            }
        } );

        if ( settings != null )
        {
            interpolator.addValueSource( new PrefixedObjectValueSource( "settings", settings ) );
        }

        String interpolatedValue = value;
        try
        {
            interpolatedValue = interpolator.interpolate( value ).trim();
        }
        catch ( InterpolationException e )
        {
        }

        if ( interpolatedValue.startsWith( "${" ) )
        {
            return null;
        }

        return interpolatedValue;
    }

    // ----------------------------------------------------------------------
    // Private methods
    // ----------------------------------------------------------------------

    /**
     * Filter the developers/contributors roles by the keys from {@link I18N#getBundle()}. <br/>
     * I18N roles supported in DOAP, i.e. <code>maintainer</code>, <code>developer</code>, <code>documenter</code>,
     * <code>translator</code>, <code>tester</code>, <code>helper</code>. <br/>
     * <b>Note:</b> Actually, only English keys are used.
     *
     * @param i18n i18n component
     * @param developersOrContributors list of <code>{@link Contributor}</code>
     * @return a none null map with <code>maintainers</code>, <code>developers</code>, <code>documenters</code>,
     *         <code>translators</code>, <code>testers</code>, <code>helpers</code>, <code>unknowns</code> as keys and
     *         list of <code>{@link Contributor}</code> as value.
     */
    private static Map<String, List<Contributor>> filterContributorsByDoapRoles( I18N i18n,
                                                                                 List<Contributor> developersOrContributors )
    {
        Map<String, List<Contributor>> returnMap = new HashMap<String, List<Contributor>>( 7 );
        returnMap.put( "maintainers", new ArrayList<Contributor>() );
        returnMap.put( "developers", new ArrayList<Contributor>() );
        returnMap.put( "documenters", new ArrayList<Contributor>() );
        returnMap.put( "translators", new ArrayList<Contributor>() );
        returnMap.put( "testers", new ArrayList<Contributor>() );
        returnMap.put( "helpers", new ArrayList<Contributor>() );
        returnMap.put( "unknowns", new ArrayList<Contributor>() );

        if ( developersOrContributors == null || developersOrContributors.isEmpty() )
        {
            return returnMap;
        }

        for ( Contributor contributor : developersOrContributors )
        {
            List<String> roles = contributor.getRoles();

            if ( roles != null && roles.size() != 0 )
            {
                for ( String role : roles )
                {
                    role = role.toLowerCase( Locale.ENGLISH );
                    if ( role.contains( getLowerCaseString( i18n, "doap.maintainer" ) ) )
                    {
                        if ( !returnMap.get( "maintainers" ).contains( contributor ) )
                        {
                            returnMap.get( "maintainers" ).add( contributor );
                        }
                    }
                    else if ( role.contains( getLowerCaseString( i18n, "doap.developer" ) ) )
                    {
                        if ( !returnMap.get( "developers" ).contains( contributor ) )
                        {
                            returnMap.get( "developers" ).add( contributor );
                        }
                    }
                    else if ( role.contains( getLowerCaseString( i18n, "doap.documenter" ) ) )
                    {
                        if ( !returnMap.get( "documenters" ).contains( contributor ) )
                        {
                            returnMap.get( "documenters" ).add( contributor );
                        }
                    }
                    else if ( role.contains( getLowerCaseString( i18n, "doap.translator" ) ) )
                    {
                        if ( !returnMap.get( "translators" ).contains( contributor ) )
                        {
                            returnMap.get( "translators" ).add( contributor );
                        }
                    }
                    else if ( role.contains( getLowerCaseString( i18n, "doap.tester" ) ) )
                    {
                        if ( !returnMap.get( "testers" ).contains( contributor ) )
                        {
                            returnMap.get( "testers" ).add( contributor );
                        }
                    }
                    else if ( role.contains( getLowerCaseString( i18n, "doap.helper" ) ) )
                    {
                        if ( !returnMap.get( "helpers" ).contains( contributor ) )
                        {
                            returnMap.get( "helpers" ).add( contributor );
                        }
                    }
                    else if ( role.contains( getLowerCaseString( i18n, "doap.emeritus" ) ) )
                    {
                        // Don't add as developer nor as contributor as the person is no longer involved
                    }
                    else
                    {
                        if ( !returnMap.get( "unknowns" ).contains( contributor ) )
                        {
                            returnMap.get( "unknowns" ).add( contributor );
                        }
                    }
                }
            }
            else
            {
                if ( !returnMap.get( "unknowns" ).contains( contributor ) )
                {
                    returnMap.get( "unknowns" ).add( contributor );
                }
            }
        }

        return returnMap;
    }

    /**
     * @param i18n not null
     * @param key not null
     * @return lower case value for the key in the i18n bundle.
     */
    private static String getLowerCaseString( I18N i18n, String key )
    {
        return i18n.getString( "doap-person", Locale.ENGLISH, key ).toLowerCase( Locale.ENGLISH );
    }

    /**
     * @return the Maven artefact version.
     */
    private static String getPluginVersion()
    {
        Properties pomProperties = new Properties();
        InputStream is = null;
        try
        {
            is =
                DoapUtil.class.getResourceAsStream( "/META-INF/maven/org.apache.maven.plugins/maven-doap-plugin/pom.properties" );
            if ( is == null )
            {
                return "<unknown>";
            }

            pomProperties.load( is );

            return pomProperties.getProperty( "version", "<unknown>" );
        }
        catch ( IOException e )
        {
            return "<unknown>";
        }
        finally
        {
            IOUtil.close( is );
        }
    }

    /**
     * Fork of {@link org.codehaus.plexus.interpolation.reflection.ReflectionValueExtractor} to care of list or arrays.
     */
    static class ReflectionValueExtractor
    {
        @SuppressWarnings( "rawtypes" )
        private static final Class[] CLASS_ARGS = new Class[0];

        private static final Object[] OBJECT_ARGS = new Object[0];

        /**
         * Use a WeakHashMap here, so the keys (Class objects) can be garbage collected. This approach prevents permgen
         * space overflows due to retention of discarded classloaders.
         */
        @SuppressWarnings( "rawtypes" )
        private static final Map<Class,ClassMap> classMaps = new WeakHashMap<Class,ClassMap>();

        private ReflectionValueExtractor()
        {
        }

        public static Object evaluate( String expression, Object root )
            throws Exception
        {
            return evaluate( expression, root, true );
        }

        // TODO: don't throw Exception
        public static Object evaluate( String expression, Object root, boolean trimRootToken )
            throws Exception
        {
            // if the root token refers to the supplied root object parameter, remove it.
            if ( trimRootToken )
            {
                expression = expression.substring( expression.indexOf( '.' ) + 1 );
            }

            Object value = root;

            // ----------------------------------------------------------------------
            // Walk the dots and retrieve the ultimate value desired from the
            // MavenProject instance.
            // ----------------------------------------------------------------------

            StringTokenizer parser = new StringTokenizer( expression, "." );

            while ( parser.hasMoreTokens() )
            {
                String token = parser.nextToken();
                if ( value == null )
                {
                    return null;
                }

                StringTokenizer parser2 = new StringTokenizer( token, "[]" );
                int index = -1;
                if ( parser2.countTokens() > 1 )
                {
                    token = parser2.nextToken();
                    try
                    {
                        index = Integer.valueOf( parser2.nextToken() ).intValue();
                    }
                    catch ( NumberFormatException e )
                    {
                    }
                }

                final ClassMap classMap = getClassMap( value.getClass() );

                final String methodBase = StringUtils.capitalizeFirstLetter( token );

                String methodName = "get" + methodBase;

                Method method = classMap.findMethod( methodName, CLASS_ARGS );

                if ( method == null )
                {
                    // perhaps this is a boolean property??
                    methodName = "is" + methodBase;

                    method = classMap.findMethod( methodName, CLASS_ARGS );
                }

                if ( method == null )
                {
                    return null;
                }

                value = method.invoke( value, OBJECT_ARGS );
                if ( value == null )
                {
                    return null;
                }
                if ( Collection.class.isAssignableFrom( value.getClass() ) )
                {
                    ClassMap classMap2 = getClassMap( value.getClass() );

                    Method method2 = classMap2.findMethod( "toArray", CLASS_ARGS );

                    value = method2.invoke( value, OBJECT_ARGS );
                }
                if ( value.getClass().isArray() )
                {
                    value = ( (Object[]) value )[index];
                }
            }

            return value;
        }

        private static ClassMap getClassMap( Class<? extends Object> clazz )
        {
            ClassMap classMap = classMaps.get( clazz );

            if ( classMap == null )
            {
                classMap = new ClassMap( clazz );

                classMaps.put( clazz, classMap );
            }

            return classMap;
        }
    }
}
TOP

Related Classes of org.apache.maven.plugin.doap.DoapUtil$ReflectionValueExtractor

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.