001    /*
002     * Copyright 2005 Stephen J. McConnell.
003     *
004     * Licensed  under the  Apache License,  Version 2.0  (the "License");
005     * you may not use  this file  except in  compliance with the License.
006     * You may obtain a copy of the License at
007     *
008     *   http://www.apache.org/licenses/LICENSE-2.0
009     *
010     * Unless required by applicable law or agreed to in writing, software
011     * distributed  under the  License is distributed on an "AS IS" BASIS,
012     * WITHOUT  WARRANTIES OR CONDITIONS  OF ANY KIND, either  express  or
013     * implied.
014     *
015     * See the License for the specific language governing permissions and
016     * limitations under the License.
017     */
018    
019    package net.dpml.library;
020    
021    import java.io.File;
022    
023    import net.dpml.lang.Version;
024    import net.dpml.lang.Enum;
025    
026    import net.dpml.transit.Artifact;
027    
028    /**
029     * Enumeration identifying resource features.
030     *
031     * @author <a href="http://www.dpml.net">Digital Product Meta Library</a>
032     * @version 1.2.0
033     */
034    public final class Feature extends Enum
035    {
036        static final long serialVersionUID = 1L;
037    
038       /**
039        * Resource name.
040        */
041        public static final Feature NAME = new Feature( "name" );
042    
043       /**
044        * Resource group.
045        */
046        public static final Feature GROUP = new Feature( "group" );
047    
048       /**
049        * Resource version.
050        */
051        public static final Feature VERSION = new Feature( "version" );
052    
053       /**
054        * Resource decimal version.
055        */
056        public static final Feature DECIMAL = new Feature( "decimal" );
057    
058       /**
059        * Resource version.
060        */
061        public static final Feature URI = new Feature( "uri" );
062    
063       /**
064        * Resource spec.
065        */
066        public static final Feature SPEC = new Feature( "spec" );
067    
068       /**
069        * Resource path.
070        */
071        public static final Feature PATH = new Feature( "path" );
072    
073       /**
074        * Resource filename.
075        */
076        public static final Feature FILENAME = new Feature( "filename" );
077    
078       /**
079        * Project basedir.
080        */
081        public static final Feature BASEDIR = new Feature( "basedir" );
082    
083       /**
084        * Array of scope enumeration values.
085        */
086        private static final Feature[] ENUM_VALUES = 
087          new Feature[]{NAME, GROUP, VERSION, DECIMAL, URI, SPEC, PATH, FILENAME, BASEDIR};
088    
089       /**
090        * Returns an array of activation enum values.
091        * @return the activation policies array
092        */
093        public static Feature[] values()
094        {
095            return ENUM_VALUES;
096        }
097        
098       /**
099        * Internal constructor.
100        * @param label the enumeration label.
101        * @param index the enumeration index.
102        */
103        private Feature( String label )
104        {
105            super( label );
106        }
107        
108       /**
109        * Return a string representation of the scope.
110        * @return the string value
111        */
112        public String toString()
113        {
114            return getName().toUpperCase();
115        }
116        
117       /**
118        * Return a feature.
119        * @param value the feature name
120        * @return the feature
121        * @exception IllegalArgumentException if the name if not a recognized feature.
122        */
123        public static Feature parse( String value ) throws IllegalArgumentException
124        {
125            if( value.equalsIgnoreCase( "name" ) )
126            {
127                return NAME;
128            }
129            else if( value.equalsIgnoreCase( "group" ) )
130            {
131                return GROUP;
132            }
133            else if( value.equalsIgnoreCase( "version" ) )
134            {
135                return VERSION;
136            }
137            else if( value.equalsIgnoreCase( "decimal" ) )
138            {
139                return DECIMAL;
140            }
141            else if( value.equalsIgnoreCase( "uri" ) )
142            {
143                return URI;
144            }
145            else if( value.equalsIgnoreCase( "spec" ) )
146            {
147                return SPEC;
148            }
149            else if( value.equalsIgnoreCase( "path" ) )
150            {
151                return PATH;
152            }
153            else if( value.equalsIgnoreCase( "filename" ) )
154            {
155                return FILENAME;
156            }
157            else if( value.equalsIgnoreCase( "basedir" ) )
158            {
159                return BASEDIR;
160            }
161            else
162            {
163                final String error =
164                  "Unrecognized feature argument [" + value + "]";
165                throw new IllegalArgumentException( error );
166            }
167        }
168        
169       /**
170        * Return the value of a feature.
171        * @param resource the target resource
172        * @param feature the feature
173        * @return the resolved value
174        */
175        public static String resolve( Resource resource, Feature feature ) 
176        {
177            return resolve( resource, feature, null, false );
178        }
179        
180       /**
181        * Return the value of a feature.
182        * @param resource the target resource
183        * @param feature the feature
184        * @param type the selected type
185        * @return the resolved value
186        */
187        public static String resolve( Resource resource, Feature feature, Type type ) 
188        {
189            return resolve( resource, feature, type, false );
190        }
191        
192       /**
193        * Return the value of a feature.
194        * @param resource the target resource
195        * @param feature the feature
196        * @param type the selected type
197        * @param alias flag indicated that alias based uri resolution is requested
198        * @return the resolved value
199        */
200        public static String resolve( Resource resource, Feature feature, Type type, boolean alias ) 
201        {
202            if( null != type && !resource.isa( type.getID() ) )
203            {
204                final String error = 
205                  "The feature request for the type [" 
206                  + type 
207                  + "] from the resource ["
208                  + resource 
209                  + "] cannot be fullfilled because the resource does not declare "
210                  + "production of the requested type.";
211                throw new FeatureRuntimeException( error );
212            }
213            
214            if( feature.equals( Feature.NAME ) )
215            {
216                return resource.getName();
217            }
218            else if( feature.equals( Feature.GROUP ) )
219            {
220                return resource.getParent().getResourcePath();
221            }
222            else if( feature.equals( Feature.VERSION ) )
223            {
224                String version = resource.getVersion();
225                if( null == version )
226                {
227                    return "";
228                }
229                else
230                {
231                    return version;
232                }
233            }
234            else if( feature.equals( Feature.DECIMAL ) )
235            {
236                Version version = resource.getDecimalVersion();
237                if( null == version )
238                {
239                    return "";
240                }
241                else
242                {
243                    return version.toString();
244                }
245            }
246            else if( feature.equals( Feature.URI ) )
247            {
248                return resolveURIFeature( resource, type, alias );
249            }
250            else if( feature.equals( Feature.SPEC ) )
251            {
252                String path = resource.getResourcePath();
253                String version =resource.getVersion();
254                if( null == version )
255                {
256                    return path;
257                }
258                else
259                {
260                    return path + "#" + version;
261                }
262            }
263            else if( feature.equals( Feature.PATH ) )
264            {
265                if( null == type )
266                {
267                    final String error = 
268                      "Type must be supplied in conjuction with the uri feature.";
269                    throw new FeatureRuntimeException( error );
270                }
271                else
272                {
273                    String id = type.getID();
274                    Artifact artifact = resource.getArtifact( id );
275                    try
276                    {
277                        File cached = 
278                          (File) artifact.toURL().getContent( new Class[]{File.class} );
279                        return cached.getCanonicalPath();
280                    }
281                    catch( Exception e )
282                    {
283                        final String error = 
284                          "Unable to resolve resource path.";
285                        throw new FeatureRuntimeException( error, e );
286                    }
287                }
288            }
289            else if( feature.equals( Feature.FILENAME ) )
290            {
291                if( null == type )
292                {
293                    final String error = 
294                      "Type must be supplied in conjuction with the filename feature.";
295                    throw new IllegalArgumentException( error );
296                }
297                String id = type.getID();
298                return resource.getLayoutPath( id );
299            }
300            else if( feature.equals( Feature.BASEDIR ) )
301            {
302                File base = resource.getBaseDir();
303                if( null == base )
304                {
305                    throw new IllegalArgumentException( "basedir" );
306                }
307                else
308                {
309                    try
310                    {
311                        return base.getCanonicalPath();
312                    }
313                    catch( Exception e )
314                    {
315                        final String error = 
316                          "Unexpected error while resolving project basedir [" + base + "].";
317                        throw new FeatureRuntimeException( error, e );
318                    }
319                }
320            }
321            else
322            {
323                final String error = 
324                  "Invalid feature [" + feature + "].";
325                throw new FeatureRuntimeException( error );
326            }
327        }
328        
329        private static String resolveURIFeature( Resource resource, Type type )
330        {
331            return resolveURIFeature( resource, type, false );
332        }
333        
334        private static String resolveURIFeature( Resource resource, Type type, boolean alias )
335        {
336            if( null == type )
337            {
338                final String error = 
339                  "Type must be supplied in conjuction with the uri feature request.";
340                throw new FeatureRuntimeException( error );
341            }
342            else
343            {
344                String id = type.getID();
345                if( alias )
346                {
347                    Version version = type.getVersion();
348                    if( null != version )
349                    {
350                        Artifact artifact = resource.getArtifact( id );
351                        String group = artifact.getGroup();
352                        String name = artifact.getName();
353                        if( Version.NULL_VERSION.equals( version ) )
354                        {
355                            return "link:" 
356                              + id 
357                              + ":" 
358                              + group
359                              + "/" 
360                              + name; 
361                        }
362                        else
363                        {
364                            int major = version.getMajor();
365                            int minor = version.getMinor();
366                            return "link:" 
367                              + id 
368                              + ":" 
369                              + group 
370                              + "/" 
371                              + name
372                              + "#"
373                              + major
374                              + "."
375                              + minor;
376                        }
377                    }
378                    else
379                    {
380                        final String error = 
381                          "Cannot resolve link from resource [" 
382                          + resource
383                          + "] because the resource does not declare production of an alias for the type ["
384                          + id 
385                          + "].";
386                        throw new FeatureRuntimeException( error );
387                    }
388                }
389                else
390                {
391                    Artifact artifact = resource.getArtifact( id );
392                    return artifact.toURI().toASCIIString();
393                }
394            }
395        }    
396    }
397