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.lib.pipeline;
016    
017    import java.util.List;
018    
019    import org.apache.hivemind.ErrorLog;
020    import org.apache.hivemind.Location;
021    import org.apache.hivemind.impl.BaseLocatable;
022    import org.apache.hivemind.lib.DefaultImplementationBuilder;
023    import org.apache.hivemind.order.Orderer;
024    import org.apache.hivemind.service.ClassFactory;
025    
026    /**
027     * Used by the {@link org.apache.hivemind.lib.pipeline.PipelineFactory} to assemble the pipeline.
028     * 
029     * @author Howard Lewis Ship
030     */
031    public class PipelineAssembler extends BaseLocatable
032    {
033        /** @since 1.1 */
034        private ErrorLog _errorLog;
035    
036        private String _serviceId;
037    
038        private Class _serviceInterface;
039    
040        private Class _filterInterface;
041    
042        private ClassFactory _classFactory;
043    
044        private DefaultImplementationBuilder _defaultBuilder;
045    
046        private Orderer _orderer;
047    
048        private Object _terminator;
049    
050        private Location _terminatorLocation;
051    
052        /**
053         * @param errorLog
054         *            used for reporting recoverable errors
055         * @param serviceInterface
056         *            the main interface
057         * @param filterInterface
058         *            the interface for filters
059         * @param classFactory
060         *            for creating new classes
061         * @param defaultBuilder
062         *            used to provide a placeholder terminator if no real terminator is supplied
063         * @param servceId
064         *            of the service being assembled
065         */
066        public PipelineAssembler(ErrorLog errorLog, String serviceId, Class serviceInterface,
067                Class filterInterface, ClassFactory classFactory,
068                DefaultImplementationBuilder defaultBuilder)
069        {
070            _errorLog = errorLog;
071            _serviceId = serviceId;
072            _serviceInterface = serviceInterface;
073            _filterInterface = filterInterface;
074            _classFactory = classFactory;
075            _defaultBuilder = defaultBuilder;
076    
077            _orderer = new Orderer(_errorLog, "filter");
078    
079        }
080    
081        public void addFilter(String name, String prereqs, String postreqs, Object filter,
082                Location location)
083        {
084            if (!checkInterface(_filterInterface, filter, location))
085                return;
086    
087            FilterHolder holder = new FilterHolder(filter, location);
088    
089            _orderer.add(holder, name, prereqs, postreqs);
090        }
091    
092        public void setTerminator(Object terminator, Location terminatorLocation)
093        {
094            if (_terminator != null)
095            {
096                _errorLog.error(PipelineMessages.duplicateTerminator(
097                        terminator,
098                        _serviceId,
099                        _terminator,
100                        _terminatorLocation), terminatorLocation, null);
101                return;
102            }
103    
104            if (!checkInterface(_serviceInterface, terminator, terminatorLocation))
105                return;
106    
107            _terminator = terminator;
108            _terminatorLocation = terminatorLocation;
109        }
110    
111        // For testing
112    
113        Object getTerminator()
114        {
115            return _terminator;
116        }
117    
118        private boolean checkInterface(Class interfaceType, Object instance, Location location)
119        {
120            if (interfaceType.isAssignableFrom(instance.getClass()))
121                return true;
122    
123            _errorLog.error(
124                    PipelineMessages.incorrectInterface(instance, interfaceType, _serviceId),
125                    location,
126                    null);
127    
128            return false;
129        }
130    
131        /**
132         * Returns an object that implements the service interface, and integrates any filters for the
133         * pipeline with the
134         */
135        public Object createPipeline()
136        {
137            List filterHolders = _orderer.getOrderedObjects();
138            int count = filterHolders.size();
139    
140            BridgeBuilder bb = (count == 0) ? null : new BridgeBuilder(_errorLog, _serviceId,
141                    _serviceInterface, _filterInterface, _classFactory);
142    
143            Object next = _terminator != null ? _terminator : _defaultBuilder
144                    .buildDefaultImplementation(_serviceInterface);
145    
146            // Like service interceptors, we work deepest (last) to shallowest (first).
147    
148            for (int i = count - 1; i >= 0; i--)
149            {
150                FilterHolder h = (FilterHolder) filterHolders.get(i);
151                Object filter = h.getFilter();
152    
153                next = bb.instantiateBridge(next, filter);
154            }
155    
156            return next;
157        }
158    }