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.station.builder;
020    
021    import java.io.IOException;
022    import java.net.URI;
023    import java.util.Properties;
024    
025    import net.dpml.station.info.RegistryDescriptor;
026    import net.dpml.station.info.RegistryDescriptor.Entry;
027    import net.dpml.station.info.ApplicationDescriptor;
028    import net.dpml.station.info.StartupPolicy;
029    
030    import net.dpml.util.DOM3DocumentBuilder;
031    
032    import net.dpml.util.DecodingException;
033    import net.dpml.util.Decoder;
034    import net.dpml.util.Resolver;
035    import net.dpml.util.SimpleResolver;
036    
037    import net.dpml.lang.ValueDirective;
038    import net.dpml.util.ElementHelper;
039    
040    import org.w3c.dom.Document;
041    import org.w3c.dom.Element;
042    
043    /**
044     * Test example application sources.
045     *
046     * @author <a href="http://www.dpml.net">Digital Product Meta Library</a>
047     * @version 1.0.5
048     */
049    public final class RegistryBuilder implements Decoder 
050    {
051        private static final DOM3DocumentBuilder DOCUMENT_BUILDER = 
052          new DOM3DocumentBuilder();
053    
054       /**
055        * Build a registry descriptior from a uri.
056        * @param uri the uri to the descriptor XML document
057        * @return the registry descriptor
058        * @exception DecodingException if a decoding error occurs
059        * @exception IOException if a IO error occurs
060        */
061        public Object build( URI uri ) throws DecodingException, IOException
062        {
063            Document document = DOCUMENT_BUILDER.parse( uri );
064            Element root = document.getDocumentElement();
065            Resolver resolver = new SimpleResolver();
066            return decode( root , resolver );
067        }
068        
069       /**
070        * Decode a registry descriptior from a DOM element.
071        * @param element the element representing the root registry
072        * @param resolver build-time uri resolver
073        * @return the registry descriptor
074        * @exception DecodingException if a decoding error occurs
075        */
076        public Object decode( Element element, Resolver resolver ) throws DecodingException
077        {
078            String tag = element.getTagName();
079            if( "application".equals( tag ) )
080            {
081                return buildApplicationDescriptor( element, resolver );
082            }
083            else if( "registry".equals( tag ) )
084            {
085                return buildRegistryDescriptor( element, resolver );
086            }
087            else
088            {
089                final String error = 
090                  "Document element name [" + tag + "] not recognized.";
091                throw new DecodingException( element, error );
092            }
093        }
094        
095        private RegistryDescriptor buildRegistryDescriptor( 
096          Element element, Resolver resolver ) throws DecodingException
097        {
098            Element[] elements = ElementHelper.getChildren( element );
099            Entry[] entries = new Entry[ elements.length ];
100            for( int i=0; i<elements.length; i++ )
101            {
102                Element elem = elements[i];
103                String key = ElementHelper.getAttribute( elem, "key" );
104                if( null == key )
105                {
106                    final String error =
107                      "Missing 'key' attribute in application element.";
108                    throw new DecodingException( elem, error );
109                }
110                ApplicationDescriptor descriptor = buildApplicationDescriptor( elem, resolver );
111                entries[i] = new Entry( key, descriptor );
112            }
113            return new RegistryDescriptor( entries );
114        }
115        
116        private ApplicationDescriptor buildApplicationDescriptor( 
117          Element element, Resolver resolver ) throws DecodingException
118        {
119            String title = ElementHelper.getAttribute( element, "title" );
120            StartupPolicy policy = buildStartupPolicy( element );
121            Element jvm = ElementHelper.getChild( element, "jvm" );
122            String base = ElementHelper.getAttribute( jvm, "base" );
123            Element startupElement = ElementHelper.getChild( jvm, "startup" );
124            Element shutdownElement = ElementHelper.getChild( jvm, "shutdown" );
125            int startup = buildTimeout( startupElement, ApplicationDescriptor.DEFAULT_STARTUP_TIMEOUT );
126            int shutdown = buildTimeout( startupElement, ApplicationDescriptor.DEFAULT_SHUTDOWN_TIMEOUT );
127            Element propertiesElement = ElementHelper.getChild( jvm, "properties" );
128            Properties properties = buildProperties( propertiesElement );
129            Element codebase = ElementHelper.getChild( element, "codebase" );
130            URI uri = decodeURI( codebase );
131            Element[] params = ElementHelper.getChildren( codebase, "param" );
132            ValueDirective[] values = buildValueDirectives( params );
133            
134            // need to rework ApplicationDescriptor such that the codebase is presented
135            // as an abstract type - e.g. net.dpml.lang.CodeBaseDirective verus 
136            // net.dpml.metro.CodeBaseDirective
137            
138            return new ApplicationDescriptor( 
139              uri, title, values, base, policy, startup, shutdown, properties, null );
140        }
141        
142        private URI decodeURI( Element element ) throws DecodingException
143        {
144            String uri = ElementHelper.getAttribute( element, "uri" );
145            if( null == uri )
146            {
147                final String error = "Missing uri attribute.";
148                throw new DecodingException( element, error );
149            }
150            else
151            {
152                try
153                {
154                    return new URI( uri );
155                }
156                catch( Exception e )
157                {
158                    final String error = "Bad uri argument [" + uri + "].";
159                    throw new DecodingException( element, error );
160                    
161                }
162            }
163        }
164    
165        private StartupPolicy buildStartupPolicy( Element element ) throws DecodingException
166        {
167            String policy = ElementHelper.getAttribute( element, "policy" );
168            if( null == policy )
169            {
170                return StartupPolicy.MANUAL;
171            }
172            else
173            {
174                return StartupPolicy.parse( policy );
175            }
176        }
177        
178        private int buildTimeout( Element element, int fallback ) throws DecodingException
179        {
180            if( null == element )
181            {
182                return fallback;
183            }
184            else
185            {
186                String value = ElementHelper.getValue( element );
187                if( null == value )
188                {
189                    return fallback;
190                }
191                else
192                {
193                    return Integer.parseInt( value );
194                }
195            }
196        }
197        
198        private Properties buildProperties( Element element ) throws DecodingException
199        {
200            Properties properties = new Properties();
201            if( null == element )
202            {
203                return properties;
204            }
205            else
206            {
207                Element[] children = ElementHelper.getChildren( element );
208                for( int i=0; i<children.length; i++ )
209                {
210                    Element child = children[i];
211                    String name = ElementHelper.getAttribute( child, "name" );
212                    if( null == name )
213                    {
214                        final String error =
215                          "Property declaration does not contain a 'name' attribute.";
216                        throw new DecodingException( child, error );
217                    }
218                    else
219                    {
220                        String value = ElementHelper.getAttribute( child, "value" );
221                        properties.setProperty( name, value );
222                    }
223                }
224                return properties;
225            }
226        }
227    
228       /**
229        * Construct a value directive array.
230        * @param elements the array of DOM elements representing value directive assertions
231        * @return the array of value directives
232        */
233        protected ValueDirective[] buildValueDirectives( Element[] elements )
234        {
235            ValueDirective[] values = new ValueDirective[ elements.length ];
236            for( int i=0; i<elements.length; i++ )
237            {
238                values[i] = buildValueDirective( elements[i] );
239            }
240            return values;
241        }
242        
243       /**
244        * Construct a single value directive.
245        * @param element the DOM element representing the value directive assertions
246        * @return the value directive
247        */
248        protected ValueDirective buildValueDirective( Element element )
249        {
250            String classname = ElementHelper.getAttribute( element, "class" );
251            String method = ElementHelper.getAttribute( element, "method" );
252            Element[] elements = ElementHelper.getChildren( element, "param" );
253            if( elements.length > 0 )
254            {
255                ValueDirective[] values = buildValueDirectives( elements );
256                return new ValueDirective( classname, method, values );
257            }
258            else
259            {
260                String value = ElementHelper.getAttribute( element, "value" );
261                return new ValueDirective( classname, method, value );
262            }
263        }
264    }