001/*
002 *  jDTAUS Core Resource Mojo
003 *  Copyright (C) 2005 Christian Schulte
004 *  <cs@schulte.it>
005 *
006 *  This library is free software; you can redistribute it and/or
007 *  modify it under the terms of the GNU Lesser General Public
008 *  License as published by the Free Software Foundation; either
009 *  version 2.1 of the License, or any later version.
010 *
011 *  This library is distributed in the hope that it will be useful,
012 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
013 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
014 *  Lesser General Public License for more details.
015 *
016 *  You should have received a copy of the GNU Lesser General Public
017 *  License along with this library; if not, write to the Free Software
018 *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
019 *
020 */
021package org.jdtaus.mojo.resource.model;
022
023import java.io.File;
024import java.io.IOException;
025import java.util.HashMap;
026import java.util.Iterator;
027import java.util.Map;
028import java.util.Properties;
029import javax.xml.bind.JAXBContext;
030import javax.xml.bind.JAXBException;
031import javax.xml.bind.Unmarshaller;
032import org.xml.sax.SAXException;
033
034/**
035 * Manages the {@code http://jdtaus.org/core/model/container} model.
036 *
037 * @author <a href="mailto:cs@schulte.it">Christian Schulte</a>
038 * @version $JDTAUS: ModelManager.java 8641 2012-09-27 06:45:17Z schulte $
039 * @plexus.component role="org.jdtaus.mojo.resource.model.ModelManager"
040 *                   role-hint="default"
041 */
042public class ModelManager
043{
044
045    /**
046     * Unmarshals a given module descriptor.
047     *
048     * @param moduleDescriptor module descriptor to unmarshall.
049     *
050     * @return the content tree unmarshalled from {@code moduleDescriptor}.
051     *
052     * @throws NullPointerException if {@code moduleDescriptor} is {@code null}.
053     * @throws JAXBException if unmarshalling fails.
054     * @throws SAXException if parsing fails.
055     * @throws IOException if reading fails.
056     */
057    public Module getModule( final File moduleDescriptor )
058        throws JAXBException, SAXException, IOException
059    {
060        Module module = null;
061        final JAXBContext ctx = JAXBContext.newInstance(
062            "org.jdtaus.mojo.resource.model" );
063
064        final Unmarshaller unmarshaller = ctx.createUnmarshaller();
065        final Object contentTree = unmarshaller.unmarshal( moduleDescriptor );
066        if ( contentTree instanceof Module )
067        {
068            module = (Module) contentTree;
069        }
070
071        return module;
072    }
073
074    /**
075     * Gets a message.
076     *
077     * @param module the module to search.
078     * @param messageName the name of the message to search.
079     *
080     * @return the message with name {@code name} from {@code module} or
081     * {@code null} if no message exists.
082     *
083     * @throws NullPointerException if {@code module} or {@code messageName} is
084     * {@code null}.
085     */
086    public Message getMessage( final Module module,
087        final String messageName )
088    {
089        if ( module == null )
090        {
091            throw new NullPointerException( "module" );
092        }
093        if ( messageName == null )
094        {
095            throw new NullPointerException( "messageName" );
096        }
097
098        Message message = null;
099
100        if ( module.getMessages() != null )
101        {
102            for ( Iterator it = module.getMessages().getMessage().iterator();
103                it.hasNext(); )
104            {
105                final Message current = (Message) it.next();
106                if ( current.getName().equals( messageName ) )
107                {
108                    message = current;
109                    break;
110                }
111            }
112        }
113
114        return message;
115    }
116
117    /**
118     * Computes the hashcode of an implementation bundle.
119     *
120     * @param module the module containing {@code implementation}.
121     * @param implementation the implementation to compute the bundle hashcode
122     * of.
123     *
124     * @return the bundle hashcode of {@code implementation}.
125     *
126     * @throws NullPointerException if {@code module} or {@code implementation}
127     * is {@code null}.
128     */
129    public int getHashCode( final Module module,
130        final Implementation implementation )
131    {
132        if ( module == null )
133        {
134            throw new NullPointerException( "module" );
135        }
136        if ( implementation == null )
137        {
138            throw new NullPointerException( "implementation" );
139        }
140
141        int bundleHash = 23;
142
143        if ( implementation.getMessages() != null )
144        {
145            for ( Iterator it = implementation.getMessages().getMessage().
146                iterator(); it.hasNext(); )
147            {
148                final Message message = (Message) it.next();
149                bundleHash = 37 * bundleHash + message.getName().hashCode();
150                for ( Iterator t = message.getTemplate().getText().iterator();
151                    t.hasNext(); )
152                {
153                    final Text text = (Text) t.next();
154                    bundleHash = 37 * bundleHash + text.getLanguage().hashCode();
155                    bundleHash = 37 * bundleHash + text.getValue().hashCode();
156                }
157
158                if ( message.getArguments() != null )
159                {
160                    for ( Iterator a = message.getArguments().getArgument().
161                        iterator(); a.hasNext(); )
162                    {
163                        final Argument argument = (Argument) a.next();
164                        bundleHash = 37 * bundleHash + argument.getName().
165                            hashCode();
166
167                        bundleHash = 37 * bundleHash + argument.getType().
168                            toString().hashCode();
169
170                    }
171                }
172            }
173
174            for ( Iterator it = implementation.getMessages().getReference().
175                iterator(); it.hasNext(); )
176            {
177                final MessageReference messageReference =
178                    (MessageReference) it.next();
179
180                final Message message =
181                    this.getMessage( module, messageReference.getName() );
182
183                for ( Iterator t = message.getTemplate().getText().iterator();
184                    t.hasNext(); )
185                {
186                    final Text text = (Text) t.next();
187                    bundleHash = 37 * bundleHash + text.getLanguage().hashCode();
188                    bundleHash = 37 * bundleHash + text.getValue().hashCode();
189                }
190
191                if ( message.getArguments() != null )
192                {
193                    for ( Iterator a = message.getArguments().getArgument().
194                        iterator(); a.hasNext(); )
195                    {
196                        final Argument argument = (Argument) a.next();
197                        bundleHash = 37 * bundleHash + argument.getName().
198                            hashCode();
199
200                        bundleHash = 37 * bundleHash + argument.getType().
201                            toString().hashCode();
202
203                    }
204                }
205            }
206        }
207
208        return bundleHash;
209    }
210
211    /**
212     * Builds a mapping of language codes to {@code Properties} instances
213     * holding the messages for the language.
214     *
215     * @param module the module containing {@code implementation}.
216     * @param implementation the implementation to get the properties for.
217     *
218     * @return mapping of language codes to {@code Properties} instances
219     * holding the messages for the language.
220     *
221     * @throws NullPointerException if {@code module} or {@code implementation}
222     * is {@code null}.
223     */
224    public Map/*<String,Properties>*/ getBundleProperties(
225        final Module module, final Implementation implementation )
226    {
227        if ( module == null )
228        {
229            throw new NullPointerException( "module" );
230        }
231        if ( implementation == null )
232        {
233            throw new NullPointerException( "implementation" );
234        }
235
236        final Map properties = new HashMap( 10 );
237
238        if ( implementation.getMessages() != null )
239        {
240            for ( Iterator it = implementation.getMessages().getMessage().
241                iterator(); it.hasNext(); )
242            {
243                final Message message = (Message) it.next();
244                for ( Iterator t = message.getTemplate().getText().iterator();
245                    t.hasNext(); )
246                {
247                    final Text text = (Text) t.next();
248                    final String language = text.getLanguage().toLowerCase();
249
250                    Properties bundleProperties =
251                        (Properties) properties.get( language );
252
253                    if ( bundleProperties == null )
254                    {
255                        bundleProperties = new Properties();
256                        properties.put( language, bundleProperties );
257                    }
258
259                    bundleProperties.setProperty( message.getName(),
260                        text.getValue() );
261
262                }
263            }
264
265            for ( Iterator it = implementation.getMessages().getReference().
266                iterator(); it.hasNext(); )
267            {
268                final MessageReference messageReference =
269                    (MessageReference) it.next();
270
271                final Message message =
272                    this.getMessage( module, messageReference.getName() );
273
274                for ( Iterator t = message.getTemplate().getText().iterator();
275                    t.hasNext(); )
276                {
277                    final Text text = (Text) t.next();
278                    final String language = text.getLanguage().toLowerCase();
279
280                    Properties bundleProperties =
281                        (Properties) properties.get( language );
282
283                    if ( bundleProperties == null )
284                    {
285                        bundleProperties = new Properties();
286                        properties.put( language, bundleProperties );
287                    }
288
289                    bundleProperties.setProperty( message.getName(),
290                        text.getValue() );
291
292                }
293            }
294        }
295
296        return properties;
297    }
298
299    /**
300     * Gets the java package name of an implementation.
301     *
302     * @param implementation the implementation to get the java package name of.
303     *
304     * @return the java package name of {@code implementation}.
305     *
306     * @throws NullPointerException if {@code implementation} is {@code null}.
307     */
308    public String getJavaPackageName( final Implementation implementation )
309    {
310        if ( implementation == null )
311        {
312            throw new NullPointerException( "implementation" );
313        }
314
315        return implementation.getIdentifier().
316            substring( 0, implementation.getIdentifier().lastIndexOf( '.' ) );
317
318    }
319
320    /**
321     * Gets the java type name of an implementation.
322     *
323     * @param implementation the implementation to get the java type name of.
324     *
325     * @return the java type name of {@code implementation}.
326     *
327     * @throws NullPointerException if {@code implementation} is {@code null}.
328     */
329    public String getJavaTypeName( final Implementation implementation )
330    {
331        if ( implementation == null )
332        {
333            throw new NullPointerException( "implementation" );
334        }
335
336        return implementation.getIdentifier().
337            substring( implementation.getIdentifier().lastIndexOf( '.' ) + 1 ) +
338            "Bundle";
339
340    }
341
342    /**
343     * Formats a text to a javadoc comment.
344     *
345     * @param text the text to nformat to a javadoc comment.
346     *
347     * @return {@code text} formatted as a javadoc comment.
348     *
349     * @throws NullPointerException if {@code text} is {@code null}.
350     */
351    public String getJavadocComment( final Text text )
352    {
353        if ( text == null )
354        {
355            throw new NullPointerException( "text" );
356        }
357
358        String normalized = text.getValue();
359        normalized = normalized.replaceAll( "\\/\\*\\*", "/*" );
360        normalized = normalized.replaceAll( "\\*/", "/" );
361        normalized = normalized.replaceAll( "\n", "\n   *" );
362        return normalized;
363    }
364
365    /**
366     * Gets the method name of a java accessor method for a given message.
367     *
368     * @param message the message to return the accessor method name for.
369     *
370     * @throws NullPointerException if {@code text} is {@code null}.
371     */
372    public String getJavaAccessorMethodName( final Message message )
373    {
374        if ( message == null )
375        {
376            throw new NullPointerException( "message" );
377        }
378
379        final char[] c = message.getName().toCharArray();
380        c[0] = Character.toUpperCase( c[0] );
381
382        return new StringBuffer( 255 ).append( "get" ).
383            append( String.valueOf( c ) ).
384            append( "Message" ).toString();
385
386    }
387
388    /**
389     * Gets the java classpath location of an implementation bundle.
390     *
391     * @return implementation the implementation to return the bundle's java
392     * classpath location of.
393     *
394     * @return the java classpath location of the bundle of
395     * {@code implementation}.
396     *
397     * @throws NullPointerException if {@code implementation} is {@code null}.
398     */
399    public String getJavaClasspathLocation( final Implementation implementation )
400    {
401        if ( implementation == null )
402        {
403            throw new NullPointerException( "implementation" );
404        }
405
406        return ( this.getJavaPackageName( implementation ) + '.' +
407            this.getJavaTypeName( implementation ) ).replace( '.', '/' );
408
409    }
410
411}