001    /*
002     * Copyright (c) 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.metro.tools;
020    
021    import java.net.URI;
022    import java.net.URISyntaxException;
023    
024    import net.dpml.component.Directive;
025    
026    import net.dpml.metro.info.PartReference;
027    import net.dpml.metro.data.ValueDirective;
028    import net.dpml.metro.data.LookupDirective;
029    import net.dpml.metro.data.NullDirective;
030    import net.dpml.metro.data.FeatureDirective;
031    import net.dpml.metro.info.EntryDescriptor;
032    import net.dpml.metro.info.Type;
033    
034    import net.dpml.lang.Value;
035    
036    import org.apache.tools.ant.BuildException;
037    
038    /**
039     * A simple part datatype.
040     *
041     * @author <a href="http://www.dpml.net">Digital Product Meta Library</a>
042     * @version 1.2.0
043     */
044    public class EntryDataType extends ValueDataType implements PartReferenceBuilder
045    {
046        private String m_key;
047        private ClassLoader m_classloader;
048        private String m_spec;
049        private int m_feature = -1;
050        private boolean m_validate = true;
051    
052       /**
053        * Set the key that this directive qualifies.
054        * @param key the context entry key
055        */
056        public void setKey( final String key )
057        {
058            m_key = key;
059        }
060    
061       /**
062        * Set the lookup attribute value.
063        * @param spec the service classname
064        */
065        public void setLookup( final String spec )
066        {
067            m_spec = spec;
068        }
069        
070       /**
071        * Set the validation flag.
072        * @param flag if false entry validation is disabled
073        */
074        public void setValidate( final boolean flag )
075        {
076            m_validate = flag;
077        }
078        
079       /**
080        * Set the feature that this directive references.
081        * @param feature the component feature
082        */
083        public void setFeature( String feature )
084        {
085            if( null != m_spec )
086            {
087                final String error = 
088                  "Attributes 'feature' and 'lookup' are mutually exlusive.";
089                throw new BuildException( error ); 
090            }
091            try
092            {
093                m_feature = FeatureDirective.getFeatureForName( feature );
094            }
095            catch( IllegalArgumentException e )
096            {
097                final String error = e.getMessage();
098                throw new BuildException( error );
099            }
100        }
101    
102        //---------------------------------------------------------------------
103        // Builder
104        //---------------------------------------------------------------------
105    
106       /**
107        * Return a uri identitifying the builder.
108        *
109        * @return the builder uri
110        */
111        public URI getBuilderURI()
112        {
113            return PART_BUILDER_URI;
114        }
115    
116        //---------------------------------------------------------------------
117        // PartReferenceBuilder
118        //---------------------------------------------------------------------
119    
120       /**
121        * Return the key identifying the part that this builder is building.
122        * @return the key
123        */
124        public String getKey()
125        {
126            if( null == m_key )
127            {
128                final String error = 
129                  "Missing 'key' attribute declaration.";
130                throw new ConstructionException( error );
131            }
132            return m_key;
133        }
134    
135       /**
136        * Return the lookup service classname.
137        * @return the classname
138        */
139        private String getLookupAttribute()
140        {
141            return m_spec;
142        }
143    
144       /**
145        * Build a part reference.
146        * @param classloader the classloader to use
147        * @param type the underlying component type
148        * @return the part reference
149        */
150        public PartReference buildPartReference( ClassLoader classloader, Type type )
151        {
152            String key = getKey();
153            if( !m_validate )
154            {
155                Directive directive = new NullDirective();
156                return new PartReference( key, directive );
157            }
158            else
159            {
160                String spec = getLookupAttribute();
161                if( null != spec )
162                {
163                    Directive directive = new LookupDirective( spec );
164                    return new PartReference( key, directive );
165                }
166                else if( m_feature > -1 )
167                {
168                    Directive directive = new FeatureDirective( key, m_feature );
169                    return new PartReference( key, directive );
170                }
171                else
172                {
173                    Directive directive = getValueDirective( classloader, type );
174                    return new PartReference( key, directive );
175                }
176            }
177        }
178    
179       /**
180        * Return a urn identitifying the part handler for this builder.
181        *
182        * @return the part handler uri
183        */
184        public URI getPartHandlerURI()
185        {
186            return PART_HANDLER_URI;
187        }
188    
189        //---------------------------------------------------------------------
190        // implementation
191        //---------------------------------------------------------------------
192    
193       /**
194        * Return the value directive.
195        * @param classloader the classloader to use
196        * @param type the underlying component type
197        * @return the value directive
198        */
199        public ValueDirective getValueDirective( ClassLoader classloader, Type type )
200        {
201            String key = getKey();
202            String classname = getClassname();
203            if( null != classname )
204            {
205                try
206                {
207                    classloader.loadClass( classname );
208                }
209                catch( ClassNotFoundException e )
210                {
211                    final String error =
212                      "Entry directive overriding class ["
213                      + classname
214                      + "] is unknown.";
215                    throw new BuildException( error, e );
216                }
217            }
218            
219            String method = getMethodName();
220    
221            if( null != type )
222            {
223                EntryDescriptor entry = type.getContextDescriptor().getEntryDescriptor( key );
224                if( null == entry )
225                {
226                    final String error = 
227                      "The value key ["
228                      + key
229                      + "] is unknown relative to the component type ["
230                      + type.getInfo().getClassname()
231                      + "].";
232                    throw new ConstructionException( error );
233                }
234                else if( null == classname )
235                {
236                    classname = entry.getClassname();
237                }
238            }
239    
240            if( null == classname )
241            {
242                final String error = 
243                  "Missing 'class' attribute for entry key ["
244                  + key 
245                  + "].";
246                throw new ConstructionException( error );
247            }
248            
249            String value = getValue();
250            if( null != value )
251            {
252                return new ValueDirective( classname, method, value );
253            }
254            else
255            {
256                ValueBuilder[] params = getValueBuilders();
257                Value[] values = new Value[ params.length ];
258                for( int i=0; i<params.length; i++ )
259                {
260                     ValueBuilder p = params[i];
261                     values[i] = p.buildValue( classloader );
262                }
263                return new ValueDirective( classname, method, values );
264            }
265        }
266    
267        //---------------------------------------------------------------------
268        // static utilities
269        //---------------------------------------------------------------------
270    
271        private static final URI PART_HANDLER_URI = setupURI( "artifact:part:dpml/metro/dpml-metro-runtime#1.2.0" );
272        private static final URI PART_BUILDER_URI = setupURI( "artifact:part:dpml/metro/dpml-metro-tools#1.2.0" );
273    
274       /**
275        * Utility function top create a static uri.
276        * @param spec the uri spec
277        * @return the uri value
278        */
279        protected static URI setupURI( String spec )
280        {
281            try
282            {
283                return new URI( spec );
284            }
285            catch( URISyntaxException ioe )
286            {
287                return null;
288            }
289        }
290    }
291