View Javadoc

1   /*
2    * ModeShape (http://www.modeshape.org)
3    * See the COPYRIGHT.txt file distributed with this work for information
4    * regarding copyright ownership.  Some portions may be licensed
5    * to Red Hat, Inc. under one or more contributor license agreements.
6    * See the AUTHORS.txt file in the distribution for a full listing of 
7    * individual contributors.
8    *
9    * ModeShape is free software. Unless otherwise indicated, all code in ModeShape
10   * is licensed to you under the terms of the GNU Lesser General Public License as
11   * published by the Free Software Foundation; either version 2.1 of
12   * the License, or (at your option) any later version.
13   * 
14   * ModeShape is distributed in the hope that it will be useful,
15   * but WITHOUT ANY WARRANTY; without even the implied warranty of
16   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17   * Lesser General Public License for more details.
18   *
19   * You should have received a copy of the GNU Lesser General Public
20   * License along with this software; if not, write to the Free
21   * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
22   * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
23   */
24  package org.modeshape.repository.cluster;
25  
26  import java.util.List;
27  import java.util.concurrent.TimeUnit;
28  import org.modeshape.common.component.ComponentLibrary;
29  import org.modeshape.common.util.CheckArg;
30  import org.modeshape.graph.ExecutionContext;
31  import org.modeshape.graph.observe.Changes;
32  import org.modeshape.graph.observe.LocalObservationBus;
33  import org.modeshape.graph.observe.ObservationBus;
34  import org.modeshape.graph.observe.Observer;
35  import org.modeshape.repository.RepositoryI18n;
36  import org.modeshape.repository.service.AbstractServiceAdministrator;
37  import org.modeshape.repository.service.AdministeredService;
38  import org.modeshape.repository.service.ServiceAdministrator;
39  
40  /**
41   * The service that provides the observation bus for a clustered (or unclustered) environment.
42   */
43  public class ClusteringService implements AdministeredService, ObservationBus {
44  
45      /**
46       * The administrative component for this service.
47       */
48      protected class Administrator extends AbstractServiceAdministrator {
49  
50          protected Administrator() {
51              super(RepositoryI18n.clusteringServiceName, State.PAUSED);
52          }
53  
54          /**
55           * {@inheritDoc}
56           */
57          @Override
58          protected void doStart( State fromState ) {
59              super.doStart(fromState);
60              startService();
61          }
62  
63          /**
64           * {@inheritDoc}
65           */
66          @Override
67          protected void doShutdown( State fromState ) {
68              super.doShutdown(fromState);
69              shutdownService();
70          }
71  
72          /**
73           * {@inheritDoc}
74           */
75          @Override
76          protected boolean doCheckIsTerminated() {
77              return isServiceTerminated();
78          }
79  
80          /**
81           * {@inheritDoc}
82           */
83          public boolean awaitTermination( long timeout,
84                                           TimeUnit unit ) {
85              return true; // nothing to wait for
86          }
87  
88      }
89  
90      private ExecutionContext executionContext;
91      private ObservationBus bus;
92      private final ComponentLibrary<ObservationBus, ClusteringConfig> busLibrary = new ComponentLibrary<ObservationBus, ClusteringConfig>();
93  
94      /**
95       * @return executionContext
96       */
97      public ExecutionContext getExecutionContext() {
98          return this.executionContext;
99      }
100 
101     /**
102      * @param executionContext Sets executionContext to the specified value.
103      */
104     public void setExecutionContext( ExecutionContext executionContext ) {
105         CheckArg.isNotNull(executionContext, "execution context");
106         if (this.getAdministrator().isStarted()) {
107             throw new IllegalStateException(RepositoryI18n.unableToChangeExecutionContextWhileRunning.text());
108         }
109         this.executionContext = executionContext;
110         this.busLibrary.setClassLoaderFactory(executionContext);
111     }
112 
113     /**
114      * Set the configuration for the clustering. This method will replace any existing configuration.
115      * 
116      * @param config the new configuration, or null if the default configuration should be used
117      * @return true if the configuration was set, or false otherwise
118      */
119     public boolean setClusteringConfig( ClusteringConfig config ) {
120         if (config == null) config = createDefaultConfiguration();
121         return this.busLibrary.removeAllAndAdd(config);
122     }
123 
124     /**
125      * {@inheritDoc}
126      * 
127      * @see org.modeshape.graph.observe.ObservationBus#hasObservers()
128      */
129     @Override
130     public boolean hasObservers() {
131         return bus != null && bus.hasObservers();
132     }
133 
134     /**
135      * {@inheritDoc}
136      * 
137      * @see org.modeshape.graph.observe.Observable#register(org.modeshape.graph.observe.Observer)
138      */
139     @Override
140     public boolean register( Observer observer ) {
141         if (bus == null) {
142             throw new IllegalStateException(RepositoryI18n.unableToRegisterObserverOnUnstartedClusteringService.text());
143         }
144         return bus.register(observer);
145     }
146 
147     /**
148      * {@inheritDoc}
149      * 
150      * @see org.modeshape.graph.observe.Observable#unregister(org.modeshape.graph.observe.Observer)
151      */
152     @Override
153     public boolean unregister( Observer observer ) {
154         if (bus == null) {
155             throw new IllegalStateException(RepositoryI18n.unableToUnregisterObserverOnUnstartedClusteringService.text());
156         }
157         return bus.unregister(observer);
158     }
159 
160     /**
161      * {@inheritDoc}
162      * 
163      * @see org.modeshape.graph.observe.Observer#notify(org.modeshape.graph.observe.Changes)
164      */
165     @Override
166     public void notify( Changes changes ) {
167         if (bus == null) {
168             throw new IllegalStateException(RepositoryI18n.unableToNotifyObserversOnUnstartedClusteringService.text());
169         }
170         bus.notify(changes);
171     }
172 
173     /**
174      * {@inheritDoc}
175      * 
176      * @see org.modeshape.repository.service.AdministeredService#getAdministrator()
177      */
178     @Override
179     public ServiceAdministrator getAdministrator() {
180         return new Administrator();
181     }
182 
183     /**
184      * {@inheritDoc}
185      * <p>
186      * This is equivalent to calling <code>getAdminstrator().start()</code> and can be called multiple times.
187      * </p>
188      * 
189      * @see org.modeshape.graph.observe.ObservationBus#start()
190      */
191     @Override
192     public void start() {
193         getAdministrator().start();
194     }
195 
196     /**
197      * {@inheritDoc}
198      * <p>
199      * This is equivalent to calling <code>getAdminstrator().shutdown()</code>.
200      * </p>
201      * 
202      * @see org.modeshape.graph.observe.ObservationBus#shutdown()
203      */
204     @Override
205     public void shutdown() {
206         getAdministrator().shutdown();
207     }
208 
209     protected void startService() {
210         List<ObservationBus> instances = busLibrary.getInstances();
211         if (instances.isEmpty()) {
212             setClusteringConfig(null);
213             instances = busLibrary.getInstances();
214             assert instances.size() > 0;
215         }
216         this.bus = instances.get(0);
217         this.bus.start();
218     }
219 
220     protected void shutdownService() {
221         // Unregister our observer ...
222         try {
223             if (this.bus != null) {
224                 this.bus.shutdown();
225             }
226         } finally {
227             this.bus = null;
228         }
229     }
230 
231     protected boolean isServiceTerminated() {
232         return this.bus != null;
233     }
234 
235     protected ClusteringConfig createDefaultConfiguration() {
236         return new ClusteringConfig("bus", "Local observation bus", LocalObservationBus.class.getName(), null);
237     }
238 }