| 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$ |
| * @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$ |
| * @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(); |
| in.close(); |
| in = null; |
| } |
| 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 ) |
| { |
| // ignore |
| } |
| 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 ) |
| { |
| // ignore |
| } |
| |
| 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 ); |
| |
| is.close(); |
| is = null; |
| |
| 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> CLASS_MAPS = 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 ) |
| { |
| // ignore |
| } |
| } |
| |
| 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 = CLASS_MAPS.get( clazz ); |
| |
| if ( classMap == null ) |
| { |
| classMap = new ClassMap( clazz ); |
| |
| CLASS_MAPS.put( clazz, classMap ); |
| } |
| |
| return classMap; |
| } |
| } |
| } |