View Javadoc

1   /*
2    * Copyright (C) 2006  Tom Gibara
3    *
4    * This library is free software; you can redistribute it and/or
5    * modify it under the terms of the GNU Lesser General Public
6    * License as published by the Free Software Foundation; either
7    * version 2.1 of the License, or (at your option) any later version.
8    *
9    * This library is distributed in the hope that it will be useful,
10   * but WITHOUT ANY WARRANTY; without even the implied warranty of
11   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12   * Lesser General Public License for more details.
13   *
14   * You should have received a copy of the GNU Lesser General Public
15   * License along with this library; if not, write to the Free Software
16   * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
17   */
18  package com.tomgibara.pronto.control.impl;
19  
20  import java.util.HashSet;
21  import java.util.logging.Logger;
22  
23  import com.tomgibara.pronto.control.ControlFactory;
24  import com.tomgibara.pronto.control.Controller;
25  import com.tomgibara.pronto.control.ControllerSettings;
26  import com.tomgibara.pronto.control.EngineControlAdapter;
27  import com.tomgibara.pronto.control.FileControllerSettings;
28  import com.tomgibara.pronto.control.ProntoControlException;
29  import com.tomgibara.pronto.control.SignalControllerSettings;
30  import com.tomgibara.pronto.control.StdinControllerSettings;
31  import com.tomgibara.pronto.state.StateEngine;
32  import com.tomgibara.pronto.util.Arguments;
33  
34  /**
35   * The standard implementation of the ControlFactory interface.
36   * 
37   * @author Tom Gibara
38   * 
39   */
40  
41  public class ControlFactoryImpl extends ControlFactory {
42  
43      // statics
44  
45      /**
46       * The log for exceptions and other log worthy events. This logger is
47       * intended to be shared by all the classes in this package.
48       */
49  
50      static final Logger LOGGER = Logger.getLogger(ControlFactoryImpl.class.getPackage().getName());
51  
52      // fields
53  
54      /**
55       * Maintains a set of part factories that are consulted when a control
56       * interface (or its implementation) is supplied to the factory.
57       */
58  
59      private final HashSet<PartFactory> factories = new HashSet<PartFactory>();
60  
61      // constructors
62  
63      public ControlFactoryImpl() {
64          // file controller
65          factories.add(new PartFactory() {
66              public boolean isSupported(final Class<? extends ControllerSettings> clss) {
67                  return FileControllerSettings.class.isAssignableFrom(clss);
68              }
69  
70              public <S, L, P> ControllerPart<S, L, P> newPart(final ControllerImpl<S, L, P> controller,
71                      final ControllerSettings settings) throws ProntoControlException {
72                  return new FileControllerPart<S, L, P>(controller, (FileControllerSettings) settings);
73              }
74          });
75  
76          // stdin controller
77          factories.add(new PartFactory() {
78              public boolean isSupported(final Class<? extends ControllerSettings> clss) {
79                  return StdinControllerSettings.class.isAssignableFrom(clss);
80              }
81  
82              public <S, L, P> ControllerPart<S, L, P> newPart(final ControllerImpl<S, L, P> controller,
83                      final ControllerSettings settings) throws ProntoControlException {
84                  return new StdinControllerPart<S, L, P>(controller, (StdinControllerSettings) settings);
85              }
86          });
87  
88          // signal controller
89          factories.add(new PartFactory() {
90              public boolean isSupported(final Class<? extends ControllerSettings> clss) {
91                  return SignalControllerSettings.class.isAssignableFrom(clss);
92              }
93  
94              public <S, L, P> ControllerPart<S, L, P> newPart(final ControllerImpl<S, L, P> controller,
95                      final ControllerSettings settings) throws ProntoControlException {
96                  return new SignalControllerPart<S, L, P>(controller, (SignalControllerSettings) settings);
97              }
98          });
99          // TODO add factory for http when we have a stronger adapter interface
100         // with all the information we might need
101     }
102 
103     @Override
104     public boolean isSettingsIfaceSupported(final Class<? extends ControllerSettings> iface) {
105         Arguments.notNull(iface, "iface");
106         if (!iface.isInterface()) throw new IllegalArgumentException("iface must be interface");
107         for (PartFactory factory : factories) {
108             if (factory.isSupported(iface)) return true;
109         }
110         return false;
111     }
112 
113     @Override
114     public <S, L, P> Controller<S, L, P> newController(final ControllerSettings settings,
115             final StateEngine<S, L, P> engine, final EngineControlAdapter<S, L, P> adapter)
116             throws ProntoControlException {
117         Arguments.notNull(settings, "settings");
118         Arguments.notNull(engine, "engine");
119         Arguments.notNull(adapter, "adapter");
120         ControllerImpl<S, L, P> controller = new ControllerImpl<S, L, P>(engine, adapter);
121 
122         for (PartFactory factory : factories) {
123             if (!factory.isSupported(settings.getClass())) continue;
124             controller.addPart(factory.newPart(controller, settings));
125         }
126 
127         if (controller.isEmpty()) throw new IllegalArgumentException(String.format("Unsupported interface: %s",
128                 settings.getClass()));
129         return controller;
130     }
131 
132     // inner classes
133 
134     /**
135      * Part factories create ControllerPart implementations that are combined by
136      * this factory to form a Controller.
137      */
138 
139     private interface PartFactory {
140 
141         /**
142          * Whether the part factory recognizes the interface.
143          * 
144          * @param iface
145          *            an interface that has been supplied to the factory
146          * @return true if this factory can create a controller from an instance
147          *         of the supplied interface
148          */
149 
150         boolean isSupported(Class<? extends ControllerSettings> iface);
151 
152         /**
153          * Creates a new controller part that draws its settings from a supplied
154          * settings object. The controller for which the part is being created
155          * is supplied to provide access to the state engine and adapter that
156          * the part is expected to operate over.
157          * 
158          * @param <S>
159          *            the state type
160          * @param <L>
161          *            the label type
162          * @param <P>
163          *            the parameter type
164          * @param controller
165          *            the controller to which the part will be added
166          * @param settings
167          *            an implementation of a settings interface
168          * @return a new instance of a controller part
169          * @throws ProntoControlException
170          */
171 
172         <S, L, P> ControllerPart<S, L, P> newPart(ControllerImpl<S, L, P> controller, ControllerSettings settings)
173                 throws ProntoControlException;
174 
175     }
176 
177 }