View Javadoc

1   /*
2    * $Id: StartableCompositeMessageSource.java 22597 2011-08-05 20:40:24Z dfeist $
3    * --------------------------------------------------------------------------------------
4    * Copyright (c) MuleSoft, Inc.  All rights reserved.  http://www.mulesoft.com
5    *
6    * The software in this package is published under the terms of the CPAL v1.0
7    * license, a copy of which has been included with this distribution in the
8    * LICENSE.txt file.
9    */
10  
11  package org.mule.source;
12  
13  import org.mule.api.MuleEvent;
14  import org.mule.api.MuleException;
15  import org.mule.api.construct.FlowConstruct;
16  import org.mule.api.construct.FlowConstructAware;
17  import org.mule.api.lifecycle.Disposable;
18  import org.mule.api.lifecycle.Initialisable;
19  import org.mule.api.lifecycle.InitialisationException;
20  import org.mule.api.lifecycle.Lifecycle;
21  import org.mule.api.lifecycle.LifecycleException;
22  import org.mule.api.lifecycle.Startable;
23  import org.mule.api.lifecycle.Stoppable;
24  import org.mule.api.processor.MessageProcessor;
25  import org.mule.api.source.CompositeMessageSource;
26  import org.mule.api.source.MessageSource;
27  import org.mule.config.i18n.CoreMessages;
28  import org.mule.util.ObjectUtils;
29  
30  import java.util.ArrayList;
31  import java.util.Collections;
32  import java.util.List;
33  import java.util.concurrent.atomic.AtomicBoolean;
34  
35  import org.apache.commons.logging.Log;
36  import org.apache.commons.logging.LogFactory;
37  
38  /**
39   * Implementation of {@link CompositeMessageSource} that propagates both injection of {@link FlowConstruct}
40   * and lifecycle to nested {@link MessageSource}s.
41   * <p>
42   * <li>This message source cannot be started without a listener set.
43   * <li>If sources are added when this composie is started they will be started as well.
44   * <li>If a {@link MessageSource} is started in isolation when composite is stopped then messages will be
45   * lost.
46   * <li>Message will only be received from endpoints if the connector is also started.
47   */
48  public class StartableCompositeMessageSource
49      implements CompositeMessageSource, Lifecycle, FlowConstructAware
50  {
51      protected static final Log log = LogFactory.getLog(StartableCompositeMessageSource.class);
52  
53      protected MessageProcessor listener;
54      protected AtomicBoolean initialised = new AtomicBoolean(false);
55      protected AtomicBoolean started = new AtomicBoolean(false);
56      protected final List<MessageSource> sources = Collections.synchronizedList(new ArrayList<MessageSource>());
57      protected AtomicBoolean starting = new AtomicBoolean(false);
58      protected FlowConstruct flowConstruct;
59      private final MessageProcessor internalListener = new InternalMessageProcessor();
60  
61      public void addSource(MessageSource source) throws MuleException
62      {
63          synchronized (sources)
64          {
65              sources.add(source);
66          }
67          source.setListener(internalListener);
68          if (initialised.get())
69          {
70              if (source instanceof FlowConstructAware)
71              {
72                  ((FlowConstructAware) source).setFlowConstruct(flowConstruct);
73              }
74              if (source instanceof Initialisable)
75              {
76                  ((Initialisable) source).initialise();
77              }
78          }
79          if (started.get() && source instanceof Startable)
80          {
81              ((Startable) source).start();
82          }
83      }
84  
85      public void removeSource(MessageSource source) throws MuleException
86      {
87          if (started.get())
88          {
89              if (source instanceof Stoppable)
90              {
91                  ((Stoppable) source).stop();
92              }
93              if (source instanceof Disposable)
94              {
95                  ((Disposable) source).dispose();
96              }
97          }
98          synchronized (sources)
99          {
100             sources.remove(source);
101         }
102     }
103     
104     public void setMessageSources(List<MessageSource> sources) throws MuleException
105     {
106         this.sources.clear();
107         for (MessageSource messageSource : sources)
108         {
109             addSource(messageSource);
110         }
111     }
112     
113     public void initialise() throws InitialisationException
114     {
115         if (listener == null)
116         {
117             throw new InitialisationException(CoreMessages.objectIsNull("listener"), this);
118         }
119         synchronized (sources)
120         {
121             for (MessageSource source : sources)
122             {
123                 if (source instanceof FlowConstructAware)
124                 {
125                     ((FlowConstructAware) source).setFlowConstruct(flowConstruct);
126                 }
127                 if (source instanceof Initialisable)
128                 {
129                     ((Initialisable) source).initialise();
130                 }
131             }
132         }
133         initialised.set(true);
134     }
135 
136     public void start() throws MuleException
137     {
138         if (listener == null)
139         {
140             throw new LifecycleException(CoreMessages.objectIsNull("listener"), this);
141         }
142 
143         synchronized (sources)
144         {
145             starting.set(true);
146             for (MessageSource source : sources)
147             {
148                 if (source instanceof Startable)
149                 {
150                     ((Startable) source).start();
151                 }
152             }
153 
154             started.set(true);
155             starting.set(false);
156         }
157     }
158 
159     public void stop() throws MuleException
160     {
161         synchronized (sources)
162         {
163             for (MessageSource source : sources)
164             {
165                 if (source instanceof Stoppable)
166                 {
167                     ((Stoppable) source).stop();
168                 }
169             }
170 
171             started.set(false);
172         }
173     }
174     
175     public void dispose()
176     {
177         synchronized (sources)
178         {
179             for (MessageSource source : sources)
180             {
181                 if (source instanceof Disposable)
182                 {
183                     ((Disposable) source).dispose();
184                 }
185             }
186         }
187     }
188 
189     public void setListener(MessageProcessor listener)
190     {
191         this.listener = listener;
192     }
193 
194     public void setFlowConstruct(FlowConstruct pattern)
195     {
196         this.flowConstruct = pattern;
197 
198     }
199     
200     @Override
201     public List<MessageSource> getSources()
202     {
203         return sources;
204     }
205 
206     @Override
207     public String toString()
208     {
209         return String.format("%s [listener=%s, sources=%s, started=%s]", getClass().getSimpleName(),
210             listener, sources, started);
211     }
212 
213     private class InternalMessageProcessor implements MessageProcessor
214     {
215         public InternalMessageProcessor()
216         {
217             super();
218         }
219 
220         public MuleEvent process(MuleEvent event) throws MuleException
221         {
222             if (started.get() || starting.get())
223             {
224                 return listener.process(event);
225             }
226             else
227             {
228                 // TODO i18n
229                 throw new IllegalStateException(String.format(
230                     "A message was receieved from MessageSource, but CompositeMessageSource is stopped.%n"
231                                     + "  Message: %s%n" + "  CompositeMessageSource: %s", event, this));
232             }
233         }
234 
235         @Override
236         public String toString()
237         {
238             return ObjectUtils.toString(this);
239         }
240     }
241 }