001    // Copyright 2004, 2005 The Apache Software Foundation
002    //
003    // Licensed under the Apache License, Version 2.0 (the "License");
004    // you may not use this file except in compliance with the License.
005    // You may obtain a copy of the License at
006    //
007    //     http://www.apache.org/licenses/LICENSE-2.0
008    //
009    // Unless required by applicable law or agreed to in writing, software
010    // distributed under the License is distributed on an "AS IS" BASIS,
011    // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
012    // See the License for the specific language governing permissions and
013    // limitations under the License.
014    
015    package org.apache.hivemind.impl;
016    
017    import java.util.List;
018    
019    import org.apache.hivemind.ApplicationRuntimeException;
020    import org.apache.hivemind.ErrorLog;
021    import org.apache.hivemind.Occurances;
022    import org.apache.hivemind.ServiceImplementationFactory;
023    import org.apache.hivemind.ServiceImplementationFactoryParameters;
024    import org.apache.hivemind.internal.Module;
025    import org.apache.hivemind.internal.ServiceImplementationConstructor;
026    import org.apache.hivemind.internal.ServicePoint;
027    import org.apache.hivemind.schema.Schema;
028    
029    /**
030     * Constructs a new service by invoking methods on another service (which implements the
031     * {@link org.apache.hivemind.ServiceImplementationFactory} interface.
032     * 
033     * @author Howard Lewis Ship
034     */
035    public final class InvokeFactoryServiceConstructor extends BaseLocatable implements
036            ServiceImplementationConstructor
037    {
038        private String _factoryServiceId;
039    
040        private ServicePoint _serviceExtensionPoint;
041    
042        private Module _contributingModule;
043    
044        /** List of {@link org.apache.hivemind.Element}, the raw XML parameters. */
045        private List _parameters;
046    
047        /** The factory service to be invoked. */
048        private ServiceImplementationFactory _factory;
049    
050        /** The parameters converted to objects as per the factory's parameter schema. */
051        private List _convertedParameters;
052    
053        public Object constructCoreServiceImplementation()
054        {
055            setupFactoryAndParameters();
056    
057            try
058            {
059                ServiceImplementationFactoryParameters factoryParameters = new ServiceImplementationFactoryParametersImpl(
060                        _serviceExtensionPoint, _contributingModule, _convertedParameters);
061    
062                return _factory.createCoreServiceImplementation(factoryParameters);
063            }
064            catch (Exception ex)
065            {
066                throw new ApplicationRuntimeException(ex.getMessage(), getLocation(), ex);
067            }
068        }
069    
070        // A lot of changes to synchronization and service construction occured between 1.1 and 1.1.1;
071        // this method was split off and made synchronized ... otherwise, it was possible for the
072        // pooled or threaded services to get into a potential race condition through this code.
073    
074        private synchronized void setupFactoryAndParameters()
075        {
076            if (_factory == null)
077            {
078                ServicePoint factoryPoint = _contributingModule.getServicePoint(_factoryServiceId);
079    
080                Occurances expected = factoryPoint.getParametersCount();
081    
082                _factory = (ServiceImplementationFactory) factoryPoint
083                        .getService(ServiceImplementationFactory.class);
084    
085                Schema schema = factoryPoint.getParametersSchema();
086    
087                ErrorLog errorLog = _serviceExtensionPoint.getErrorLog();
088    
089                SchemaProcessorImpl processor = new SchemaProcessorImpl(errorLog, schema);
090    
091                processor.process(_parameters, _contributingModule);
092    
093                _convertedParameters = processor.getElements();
094    
095                checkParameterCounts(errorLog, expected);
096            }
097        }
098    
099        /**
100         * Checks that the number of parameter elements matches the expected count.
101         */
102        private void checkParameterCounts(ErrorLog log, Occurances expected)
103        {
104            int actual = _convertedParameters.size();
105    
106            if (expected.inRange(actual))
107                return;
108    
109            String message = ImplMessages.wrongNumberOfParameters(_factoryServiceId, actual, expected);
110    
111            log.error(message, getLocation(), null);
112        }
113    
114        public Module getContributingModule()
115        {
116            return _contributingModule;
117        }
118    
119        public void setContributingModule(Module module)
120        {
121            _contributingModule = module;
122        }
123    
124        public List getParameters()
125        {
126            return _parameters;
127        }
128    
129        public ServicePoint getServiceExtensionPoint()
130        {
131            return _serviceExtensionPoint;
132        }
133    
134        public void setParameters(List list)
135        {
136            _parameters = list;
137        }
138    
139        public void setFactoryServiceId(String string)
140        {
141            _factoryServiceId = string;
142        }
143    
144        public void setServiceExtensionPoint(ServicePoint point)
145        {
146            _serviceExtensionPoint = point;
147        }
148    
149    }