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