KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > jboss > mq > sm > file > DynamicStateManager


1 /*
2 * JBoss, Home of Professional Open Source
3 * Copyright 2005, JBoss Inc., and individual contributors as indicated
4 * by the @authors tag. See the copyright.txt in the distribution for a
5 * full listing of individual contributors.
6 *
7 * This is free software; you can redistribute it and/or modify it
8 * under the terms of the GNU Lesser General Public License as
9 * published by the Free Software Foundation; either version 2.1 of
10 * the License, or (at your option) any later version.
11 *
12 * This software is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
16 *
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this software; if not, write to the Free
19 * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
20 * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
21 */

22 package org.jboss.mq.sm.file;
23
24 import java.io.File JavaDoc;
25 import java.io.FileOutputStream JavaDoc;
26 import java.io.PrintStream JavaDoc;
27 import java.io.InputStream JavaDoc;
28 import java.io.BufferedInputStream JavaDoc;
29 import java.io.IOException JavaDoc;
30 import java.net.URL JavaDoc;
31 import java.util.ArrayList JavaDoc;
32 import java.util.Collection JavaDoc;
33 import java.util.Enumeration JavaDoc;
34
35 import javax.jms.InvalidClientIDException JavaDoc;
36 import javax.jms.JMSException JavaDoc;
37 import javax.jms.JMSSecurityException JavaDoc;
38
39 import org.jboss.system.server.ServerConfigLocator;
40 import org.jboss.mq.DurableSubscriptionID;
41 import org.jboss.mq.SpyTopic;
42 import org.jboss.mq.SpyJMSException;
43 import org.jboss.mq.xml.XElement;
44 import org.jboss.mq.xml.XElementException;
45
46 import org.jboss.mq.sm.StateManager;
47 import org.jboss.mq.sm.AbstractStateManager;
48
49 /**
50  * A state manager that allowed durable subscriptions to be dynamically
51  * created if configured to support it. Otherwise backward compatible with
52  * the old StateManager.
53  *
54  * <p>Backed by an XML file.
55  *
56  * <p>Example file format:
57  * <xmp>
58 <StateManager>
59  <Users>
60    <User>
61     <Name>john</Name>
62     <Password>needle</Password>
63     <Id>DurableSubscriberExample</Id><!-- optional -->
64    </User>
65  </Users>
66
67  <Roles>
68   <Role name="guest">
69     <UserName>john</UserName>
70   </Role>
71
72  </Roles>
73
74  <DurableSubscriptions>
75    <DurableSubscription>
76      <ClientID>needle</ClientID>
77      <Name>myDurableSub</Name>
78      <TopicName>TestTopic...</TopicName>
79    </DurableSubscription>
80
81  </DurableSubscriptions>
82 </StateManager>
83  * </xmp>
84  *
85  * @jmx:mbean extends="org.jboss.mq.sm.AbstractStateManagerMBean"
86  *
87  * @author <a HREF="Norbert.Lataille@m4x.org">Norbert Lataille</a>
88  * @author <a HREF="hiram.chirino@jboss.org">Hiram Chirino</a>
89  * @author <a HREF="pra@tim.se">Peter Antman</a>
90  * @version $Revision: 37459 $
91  */

92 public class DynamicStateManager extends AbstractStateManager implements DynamicStateManagerMBean
93 {
94    class DynamicDurableSubscription extends DurableSubscription
95    {
96       XElement element;
97       public DynamicDurableSubscription(XElement element) throws XElementException
98       {
99          super(
100             element.getField("ClientID"),
101             element.getField("Name"),
102             element.getField("TopicName"),
103             element.getOptionalField("Selector"));
104          this.element = element;
105       }
106       XElement getElement()
107       {
108          return element;
109       }
110
111       // Hm, I don't think we should mutate it without a sync.
112
//public void setTopic(String topic) {
113
// this.topic = topic;
114
// element.setField("Topic", topic);
115
// }
116

117    }
118
119    /**
120     * Do we have a security manager.
121     *
122     * By setting this to false, we may emulate the old behaviour of
123     * the state manager and let it autenticate connections.
124     */

125    boolean hasSecurityManager = true;
126
127    XElement stateConfig = new XElement("StateManager"); //So sync allways work
128

129    /** State file is relateive to systemConfigURL. */
130    private String JavaDoc stateFile = "jbossmq-state.xml";
131    private URL JavaDoc systemConfigURL;
132
133    public DynamicStateManager()
134    {
135
136    }
137    //
138
// MBean methods
139
//
140
public StateManager getInstance()
141    {
142       return this;
143    }
144
145    protected void createService() throws Exception JavaDoc
146    {
147       // Get the system configuration URL
148
systemConfigURL = ServerConfigLocator.locate().getServerConfigURL();
149    }
150
151    public void startService() throws Exception JavaDoc
152    {
153       loadConfig();
154    }
155
156    /**
157     * Show the current configuration.
158     */

159    public String JavaDoc displayStateConfig() throws Exception JavaDoc
160    {
161       return stateConfig.toString();
162    }
163
164    /**
165     * Set the name of the statefile.
166     *
167     * @jmx:managed-attribute
168     *
169     * @param newStateFile java.lang.String
170     */

171    public void setStateFile(String JavaDoc newStateFile)
172    {
173       stateFile = newStateFile.trim();
174    }
175
176    /**
177     * Get name of file.
178     *
179     * @jmx:managed-attribute
180     *
181     * @return java.lang.String
182     */

183    public String JavaDoc getStateFile()
184    {
185       return stateFile;
186    }
187
188    /**
189     * @jmx:managed-attribute
190     */

191    public boolean hasSecurityManager()
192    {
193       return hasSecurityManager;
194    }
195
196    /**
197     * @jmx:managed-attribute
198     */

199    public void setHasSecurityManager(boolean hasSecurityManager)
200    {
201       this.hasSecurityManager = hasSecurityManager;
202    }
203
204    /**
205     * @jmx:managed-operation
206     */

207    public void loadConfig() throws IOException JavaDoc, XElementException
208    {
209       URL JavaDoc configURL = new URL JavaDoc(systemConfigURL, stateFile);
210       if (log.isDebugEnabled())
211       {
212          log.debug("Loading config from: " + configURL);
213       }
214
215       InputStream JavaDoc in = new BufferedInputStream JavaDoc(configURL.openStream());
216       try
217       {
218          synchronized (stateConfig)
219          {
220             stateConfig = XElement.createFrom(in);
221          }
222       }
223       finally
224       {
225          in.close();
226       }
227    }
228
229    /**
230     * @jmx:managed-operation
231     */

232    public void saveConfig() throws IOException JavaDoc
233    {
234       URL JavaDoc configURL = new URL JavaDoc(systemConfigURL, stateFile);
235
236       if (configURL.getProtocol().equals("file"))
237       {
238          File JavaDoc file = new File JavaDoc(configURL.getFile());
239          if (log.isDebugEnabled())
240          {
241             log.debug("Saving config to: " + file);
242          }
243
244          PrintStream JavaDoc stream = new PrintStream JavaDoc(new FileOutputStream JavaDoc(file));
245          try
246          {
247             synchronized (stateConfig)
248             {
249                stream.print(stateConfig.toXML(true));
250             }
251          }
252          finally
253          {
254             stream.close();
255          }
256       }
257       else
258       {
259          log.error("Can not save configuration to non-file URL: " + configURL);
260       }
261    }
262    //
263
// Callback methods from AbstractStateManager
264
//
265
/**
266     * Return preconfigured client id. Only if hasSecurityManager is false will
267     * a password be required to get the clientID and will the method throw
268     * a JMSSecurityException if the clientID was not found.
269     */

270    protected String JavaDoc getPreconfClientId(String JavaDoc login, String JavaDoc passwd) throws JMSException JavaDoc
271    {
272       try
273       {
274          synchronized (stateConfig)
275          {
276
277             Enumeration JavaDoc enumeration = stateConfig.getElementsNamed("Users/User");
278             while (enumeration.hasMoreElements())
279             {
280                XElement element = (XElement) enumeration.nextElement();
281                String JavaDoc name = element.getField("Name");
282                if (!name.equals(login))
283                {
284                   continue; // until user is found
285
}
286
287                // Onlyn check password if we do not have a security manager
288
if (!hasSecurityManager)
289                {
290                   String JavaDoc pw = element.getField("Password");
291                   if (!passwd.equals(pw))
292                   {
293                      throw new JMSSecurityException JavaDoc("Bad password");
294                   }
295                }
296
297                String JavaDoc clientId = null;
298                if (element.containsField("Id"))
299                {
300                   clientId = element.getField("Id");
301                }
302
303                //if (clientId != null)
304
return clientId;
305             }
306             if (!hasSecurityManager)
307                throw new JMSSecurityException JavaDoc("This user does not exist");
308             else
309                return null;
310          }
311       }
312       catch (XElementException e)
313       {
314          log.error(e);
315          throw new JMSException JavaDoc("Invalid server user configuration.");
316       }
317    }
318
319    /**
320     * Search for a configurated durable subscription.
321     */

322    protected DurableSubscription getDurableSubscription(DurableSubscriptionID sub) throws JMSException JavaDoc
323    {
324       boolean debug = log.isDebugEnabled();
325
326       //Set the known Ids
327
try
328       {
329          synchronized (stateConfig)
330          {
331
332             Enumeration JavaDoc enumeration = stateConfig.getElementsNamed("DurableSubscriptions/DurableSubscription");
333             while (enumeration.hasMoreElements())
334             {
335
336                // Match ID
337
XElement dur = (XElement) enumeration.nextElement();
338                if (dur.containsField("ClientID") && dur.getField("ClientID").equals(sub.getClientID()))
339                {
340                   // Check if this one has a DurableSubname that match
341
if (dur.getField("Name").equals(sub.getSubscriptionName()))
342                   {
343                      // We have a match
344
if (debug)
345                         log.debug("Found a matching ClientID configuration section.");
346                      return new DynamicDurableSubscription(dur);
347                   }
348
349                }
350             }
351             // Nothing found
352
return null;
353          }
354       }
355       catch (XElementException e)
356       {
357          JMSException JavaDoc newE = new SpyJMSException("Could not find durable subscription");
358          newE.setLinkedException(e);
359          throw newE;
360       }
361    }
362
363    /**
364     * Check if the clientID belonges to a preconfigured user. If this
365     * is the case, a InvalidClientIDException will be raised.
366     */

367    protected void checkLoggedOnClientId(String JavaDoc clientID) throws JMSException JavaDoc
368    {
369       synchronized (stateConfig)
370       {
371
372          Enumeration JavaDoc enumeration = stateConfig.getElementsNamed("Users/User");
373          while (enumeration.hasMoreElements())
374          {
375             XElement element = (XElement) enumeration.nextElement();
376             try
377             {
378                if (element.containsField("Id") && element.getField("Id").equals(clientID))
379                {
380                   throw new InvalidClientIDException JavaDoc("This loggedOnClientIds is password protected !");
381                }
382             }
383             catch (XElementException ignore)
384             {
385             }
386          }
387       }
388
389    }
390    protected void saveDurableSubscription(DurableSubscription ds) throws JMSException JavaDoc
391    {
392       try
393       {
394          synchronized (stateConfig)
395          {
396             // Or logic here is simply this, if we get a DynamicDurableSubscription
397
// Its reconfiguration, if not it is new
398
if (ds instanceof DynamicDurableSubscription)
399             {
400                XElement s = ((DynamicDurableSubscription) ds).getElement();
401                if (s != null)
402                {
403                   s.setField("TopicName", ds.getTopic()); //In case it changed.
404
s.setOptionalField("Selector", ds.getSelector()); //In case it changed.
405
}
406                else
407                {
408                   throw new JMSException JavaDoc("Can not save a null subscription");
409                }
410             }
411             else
412             {
413                XElement dur = stateConfig.getElement("DurableSubscriptions");
414                XElement subscription = new XElement("DurableSubscription");
415                subscription.addField("ClientID", ds.getClientID());
416                subscription.addField("Name", ds.getName());
417                subscription.addField("TopicName", ds.getTopic());
418                subscription.setOptionalField("Selector", ds.getSelector());
419                dur.addElement(subscription);
420             }
421             saveConfig();
422          }
423       }
424       catch (XElementException e)
425       {
426          JMSException JavaDoc newE = new SpyJMSException("Could not save the durable subscription");
427          newE.setLinkedException(e);
428          throw newE;
429       }
430       catch (IOException JavaDoc e)
431       {
432          JMSException JavaDoc newE = new SpyJMSException("Could not save the durable subscription");
433          newE.setLinkedException(e);
434          throw newE;
435       }
436    }
437    protected void removeDurableSubscription(DurableSubscription ds) throws JMSException JavaDoc
438    {
439       try
440       {
441          // We only remove if it was our own dur sub.
442
synchronized (stateConfig)
443          {
444             XElement s = ((DynamicDurableSubscription) ds).getElement();
445             if (s != null)
446             {
447                s.removeFromParent();
448                saveConfig();
449             }
450             else
451             {
452                throw new JMSException JavaDoc("Can not remove a null subscription");
453             }
454          }
455       }
456       catch (XElementException e)
457       {
458          JMSException JavaDoc newE = new SpyJMSException("Could not remove the durable subscription");
459          newE.setLinkedException(e);
460          throw newE;
461       }
462       catch (IOException JavaDoc e)
463       {
464          JMSException JavaDoc newE = new SpyJMSException("Could not remove the durable subscription");
465          newE.setLinkedException(e);
466          throw newE;
467       }
468    }
469
470    public Collection JavaDoc getDurableSubscriptionIdsForTopic(SpyTopic topic) throws JMSException JavaDoc
471    {
472       Collection JavaDoc durableSubs = new ArrayList JavaDoc();
473       try
474       {
475          synchronized (stateConfig)
476          {
477
478             Enumeration JavaDoc enumeration = stateConfig.getElementsNamed("DurableSubscriptions/DurableSubscription");
479             while (enumeration.hasMoreElements())
480             {
481                XElement element = (XElement) enumeration.nextElement();
482
483                String JavaDoc clientId = element.getField("ClientID");
484                String JavaDoc name = element.getField("Name");
485                String JavaDoc topicName = element.getField("TopicName");
486                String JavaDoc selector = element.getOptionalField("Selector");
487                if (topic.getName().equals(topicName))
488                {
489                   durableSubs.add(new DurableSubscriptionID(clientId, name, selector));
490                } // end of if ()
491

492             }
493          }
494       }
495       catch (XElementException e)
496       {
497          JMSException JavaDoc jmse = new JMSException JavaDoc("Error in statemanager xml");
498          jmse.setLinkedException(e);
499          throw jmse;
500       } // end of try-catch
501
return durableSubs;
502    }
503
504    //
505
// The methods that allow dynamic edititing of state manager.
506
//
507

508    /**
509     * @jmx:managed-operation
510     */

511    public void addUser(String JavaDoc name, String JavaDoc password, String JavaDoc preconfID) throws Exception JavaDoc
512    {
513       if (findUser(name) != null)
514          throw new Exception JavaDoc("Can not add, user exist");
515
516       XElement users = stateConfig.getElement("Users");
517       XElement user = new XElement("User");
518       user.addField("Name", name);
519       user.addField("Password", password);
520       if (preconfID != null)
521          user.addField("Id", preconfID);
522       users.addElement(user);
523       saveConfig();
524    }
525
526    /**
527     * @jmx:managed-operation
528     */

529    public void removeUser(String JavaDoc name) throws Exception JavaDoc
530    {
531       XElement user = findUser(name);
532       if (user == null)
533          throw new Exception JavaDoc("Cant remove user that does not exist");
534
535       user.removeFromParent();
536
537       // We should also remove the user from any roles it belonges to
538
String JavaDoc[] roles = getRoles(name);
539       if (roles != null)
540       {
541          for (int i = 0; i < roles.length; i++)
542          {
543             try
544             {
545                removeUserFromRole(roles[i], name);
546             }
547             catch (Exception JavaDoc ex)
548             {
549                //Just move on
550
}
551          }
552       }
553
554       saveConfig();
555    }
556
557    /**
558     * @jmx:managed-operation
559     */

560    public void addRole(String JavaDoc name) throws Exception JavaDoc
561    {
562       if (findRole(name) != null)
563          throw new Exception JavaDoc("Cant add role, it already exists");
564
565       XElement roles = stateConfig.getElement("Roles");
566       XElement role = new XElement("Role");
567       role.setAttribute("name", name);
568       roles.addElement(role);
569       saveConfig();
570    }
571
572    /**
573     * @jmx:managed-operation
574     */

575    public void removeRole(String JavaDoc name) throws Exception JavaDoc
576    {
577       XElement role = findRole(name);
578       if (role == null)
579          throw new Exception JavaDoc("Cant remove role that does not exist");
580
581       role.removeFromParent();
582       saveConfig();
583    }
584
585    // FIXME; no sanity check that the "real" user does exist.
586
/**
587     * @jmx:managed-operation
588     */

589    public void addUserToRole(String JavaDoc roleName, String JavaDoc user) throws Exception JavaDoc
590    {
591       XElement role = findRole(roleName);
592       if (role == null)
593          throw new Exception JavaDoc("Cant add to role that does not exist");
594
595       if (findUser(user) == null)
596          throw new Exception JavaDoc("Cant add user to role, user does to exist");
597
598       if (findUserInRole(role, user) != null)
599          throw new Exception JavaDoc("Cant add user to role, user already part of role");
600       // FIXME; here I am not shure how XElement work
601
XElement u = new XElement("UserName");
602       u.setValue(user);
603       role.addElement(u);
604       saveConfig();
605    }
606
607    /**
608     * @jmx:managed-operation
609     */

610    public void removeUserFromRole(String JavaDoc roleName, String JavaDoc user) throws Exception JavaDoc
611    {
612       XElement role = findRole(roleName);
613       if (role == null)
614          throw new Exception JavaDoc("Cant remove user from role that does not exist");
615
616       XElement u = findUserInRole(role, user);
617       if (u == null)
618          throw new Exception JavaDoc("Cant remove user from role, user does not exist");
619       u.removeFromParent();
620       saveConfig();
621
622    }
623
624    protected XElement findUser(String JavaDoc user) throws Exception JavaDoc
625    {
626       Enumeration JavaDoc enumeration = stateConfig.getElementsNamed("Users/User");
627       while (enumeration.hasMoreElements())
628       {
629          XElement element = (XElement) enumeration.nextElement();
630          if (element.getField("Name").equals(user))
631             return element;
632       }
633       return null;
634    }
635
636    protected XElement findRole(String JavaDoc role) throws Exception JavaDoc
637    {
638       Enumeration JavaDoc enumeration = stateConfig.getElementsNamed("Roles/Role");
639       while (enumeration.hasMoreElements())
640       {
641          XElement element = (XElement) enumeration.nextElement();
642          if (element.getAttribute("name").equals(role))
643             return element;
644       }
645       return null;
646    }
647
648    protected XElement findUserInRole(XElement role, String JavaDoc user) throws Exception JavaDoc
649    {
650       Enumeration JavaDoc enumeration = role.getElementsNamed("UserName");
651       while (enumeration.hasMoreElements())
652       {
653          XElement element = (XElement) enumeration.nextElement();
654          if (user.equals(element.getValue()))
655             return element;
656       }
657       return null;
658    }
659    //
660
// Methods to support LoginModule
661
//
662
/**
663     * We currently only support one Group type Roles. The role named
664     * returned should typically be put into a Roles Group principal.
665     */

666    public String JavaDoc[] getRoles(String JavaDoc user) throws Exception JavaDoc
667    {
668       ArrayList JavaDoc roles = new ArrayList JavaDoc();
669       Enumeration JavaDoc enumeration = stateConfig.getElementsNamed("Roles/Role");
670       while (enumeration.hasMoreElements())
671       {
672          XElement element = (XElement) enumeration.nextElement();
673          XElement u = findUserInRole(element, user);
674          if (u != null)
675             roles.add(element.getAttribute("name"));
676       }
677       return (String JavaDoc[]) roles.toArray(new String JavaDoc[roles.size()]);
678    }
679
680    /**
681     * Validate the user/password combination. A null inputPassword will
682     * allways reurn false.
683     */

684    public boolean validatePassword(String JavaDoc user, String JavaDoc inputPassword) throws Exception JavaDoc
685    {
686       boolean valid = false;
687       XElement u = findUser(user);
688       if (u != null)
689       {
690          String JavaDoc pw = u.getField("Password");
691          if (inputPassword != null && inputPassword.equals(pw))
692             valid = true;
693       }
694       return valid;
695    }
696
697    //
698
// Helper methods
699
//
700

701 } // DynamicStateManager
702
Popular Tags