001    /*
002     * Copyright 2006 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.component;
020    
021    import java.io.IOException;
022    import java.net.URI;
023    import java.lang.ref.WeakReference;
024    
025    import net.dpml.lang.Classpath;
026    import net.dpml.lang.Info;
027    import net.dpml.lang.Part;
028    
029    import net.dpml.util.Logger;
030    
031    /**
032     * Component composition.
033     *
034     * @author <a href="http://www.dpml.net">Digital Product Meta Library</a>
035     * @version 1.2.0
036     */
037    public abstract class Composition extends Part implements Directive
038    {
039        private final Directive m_directive;
040        private final Controller m_controller;
041        
042        private transient WeakReference m_model;
043        
044       /**
045        * Creation of a new abstract composition instance.
046        * @param logger the assigned logging channel
047        * @param info the part info descriptor
048        * @param classpath the part classpath definition
049        * @param controller the part controller
050        * @param directive the part deployment strategy directive
051        * @param label debug label
052        * @exception IOException if an I/O error occurs
053        */
054        public Composition( 
055          Logger logger, Info info, Classpath classpath, Controller controller, 
056          Directive directive, String label ) throws IOException
057        {
058            super( logger, info, classpath, label );
059            
060            if( null == directive )
061            {
062                throw new NullPointerException( "directive" );
063            }
064            m_directive = directive;
065            m_controller = controller;
066        }
067        
068       /**
069        * Return the assigned controller.
070        * @return the controller
071        */
072        public Controller getController()
073        {
074            return m_controller;
075        }
076    
077       /**
078        * Return the part content or null if the result type is unresolvable 
079        * relative to the supplied class argument. Class types recognized over and 
080        * above the Part class include Directive, Model, Component and Controller.
081        *
082        * @param c the content class
083        * @return the content
084        * @exception IOException if an IO error occurs
085        */
086        protected Object getContent( Class c ) throws IOException
087        {
088            if( Directive.class.isAssignableFrom( c ) )
089            {
090                return m_directive;
091            }
092            else if( Model.class.isAssignableFrom( c ) )
093            {
094                return getModel();
095            }
096            else if( Component.class.isAssignableFrom( c ) )
097            {
098                return newComponent();
099            }
100            else if( Controller.class.isAssignableFrom( c ) )
101            {
102                return m_controller;
103            }
104            else
105            {
106                return super.getContent( c );
107            }
108        }
109        
110       /**
111        * Get the deployment directive.
112        * @return the deployment directive
113        */
114        public Directive getDirective()
115        {
116            return m_directive;
117        }
118        
119       /**
120        * Get the deployment model.
121        * @return the deployment model
122        */
123        public Model getModel()
124        {
125            if( null != m_model )
126            {
127                Model model = (Model) m_model.get();
128                if( null != model )
129                {
130                    return model;
131                }
132            }
133            try
134            {
135                Model model = m_controller.createModel( this );
136                m_model = new WeakReference( model );
137                return model;
138            }
139            catch( Throwable e )
140            {
141                URI uri = m_controller.getURI();
142                final String error = 
143                  "Unexpected error while attempting to create a component model."
144                  + "\nDirective: " + m_directive;
145                throw new ControlRuntimeException( uri, error, e );
146            }
147        }
148        
149       /**
150        * Create and return a new component using the deplyment model established by the part.
151        * @return the component
152        */
153        public Component newComponent()
154        {
155            Model model = getModel();
156            try
157            {
158                return m_controller.createComponent( model );
159            }
160            catch( Throwable e )
161            {
162                URI uri = m_controller.getURI();
163                final String error = 
164                  "Unexpected error while attempting to create a component."
165                  + "\nDirective: " + m_directive;
166                throw new ControlRuntimeException( uri, error, e );
167            }
168        }
169        
170       /**
171        * Instantiate a value.
172        * @param args supplimentary arguments
173        * @return the resolved instance
174        * @exception Exception if a deployment error occurs
175        */
176        public Object instantiate( Object[] args ) throws Exception
177        {
178            Component component = newComponent();
179            return component.getProvider().getValue( false );
180        }
181        
182       /**
183        * Return true if this object is equal to the supplied object.
184        * @param other the object to evaluate
185        * @return the equality status
186        */
187        public boolean equals( Object other )
188        {
189            if( super.equals( other ) && ( other instanceof Composition ) )
190            {
191                Composition composite = (Composition) other;
192                if( !m_directive.equals( composite.m_directive ) )
193                {
194                    return false;
195                }
196                else
197                {
198                    if( null == m_controller )
199                    {
200                        return null == composite.m_controller;
201                    }
202                    else
203                    {
204                        return m_controller.equals( composite.m_controller );
205                    }
206                }
207            }
208            else
209            {
210                return false;
211            }
212        }
213        
214       /**
215        * Return the hashcode for the instance.
216        * @return the instance hashcode
217        */
218        public int hashCode()
219        {
220            int hash = super.hashCode();
221            hash ^= m_directive.hashCode();
222            if( null != m_controller )
223            {
224                hash ^= m_controller.hashCode();
225            }
226            return hash;
227        }
228    }