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
015package org.apache.hivemind.impl;
016
017import java.util.List;
018
019import org.apache.hivemind.ApplicationRuntimeException;
020import org.apache.hivemind.ErrorLog;
021import org.apache.hivemind.Occurances;
022import org.apache.hivemind.ServiceImplementationFactory;
023import org.apache.hivemind.ServiceImplementationFactoryParameters;
024import org.apache.hivemind.internal.Module;
025import org.apache.hivemind.internal.ServiceImplementationConstructor;
026import org.apache.hivemind.internal.ServicePoint;
027import 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 */
035public 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}