KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > james > transport > mailets > CommandListservManager


1 /***********************************************************************
2  * Copyright (c) 2000-2004 The Apache Software Foundation. *
3  * All rights reserved. *
4  * ------------------------------------------------------------------- *
5  * Licensed under the Apache License, Version 2.0 (the "License"); you *
6  * may not use this file except in compliance with the License. You *
7  * may obtain a copy of the License at: *
8  * *
9  * http://www.apache.org/licenses/LICENSE-2.0 *
10  * *
11  * Unless required by applicable law or agreed to in writing, software *
12  * distributed under the License is distributed on an "AS IS" BASIS, *
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or *
14  * implied. See the License for the specific language governing *
15  * permissions and limitations under the License. *
16  ***********************************************************************/

17
18 package org.apache.james.transport.mailets;
19
20 import org.apache.avalon.framework.component.ComponentManager;
21 import org.apache.avalon.framework.configuration.Configuration;
22 import org.apache.avalon.framework.configuration.ConfigurationException;
23 import org.apache.james.Constants;
24 import org.apache.james.services.UsersRepository;
25 import org.apache.james.services.UsersStore;
26 import org.apache.james.transport.mailets.listservcommands.ErrorCommand;
27 import org.apache.james.transport.mailets.listservcommands.IListServCommand;
28 import org.apache.james.util.XMLResources;
29 import org.apache.mailet.GenericMailet;
30 import org.apache.mailet.Mail;
31 import org.apache.mailet.MailAddress;
32
33 import javax.mail.MessagingException JavaDoc;
34 import java.io.File JavaDoc;
35 import java.lang.reflect.Field JavaDoc;
36 import java.util.*;
37
38 /**
39  * CommandListservManager is the default implementation of {@link ICommandListservManager}.
40  * It loads all the configured {@link IListServCommand}s and delegates to them at runtime.
41  * <br />
42  *
43  * It isn't responsible for procesing messages sent to the main mailing list, but is responsible for
44  * individual commands sent by users, such as: info, subscribe, etc...
45  * <br />
46  *
47  * Requests sent to the CommandListservManager take the form of:
48  * <pre>
49  * &lt;listName&gt;-&lt;commandName&gt;@domain
50  * </pre>
51  *
52  * If the command isn't recognized an error will be sent using {@link #onError}.
53  * <br />
54  * <br />
55  *
56  * The configuration for this mailet sould be in the 'root' processor block.
57  * <pre>
58  * &lt;mailet match="CommandListservMatcher=announce@localhost" class="CommandListservManager"&gt;
59  * &lt;listName&gt;announce&lt;/listName&gt;
60  * &lt;displayName&gt;Announce mailing list&lt;/displayName&gt;
61  * &lt;listOwner&gt;owner@localhost&lt;/listOwner&gt;
62  * &lt;repositoryName&gt;list-announce&lt;/repositoryName&gt;
63  * &lt;listDomain&gt;localhost&lt;/listDomain&gt;
64  *
65  * &lt;commandpackages&gt;
66  * &lt;commandpackage&gt;org.apache.james.transport.mailets.listservcommands&lt;/commandpackage&gt;
67  * &lt;/commandpackages&gt;
68  *
69  * &lt;commands&gt;
70  * &lt;command name="subscribe" class="Subscribe"/&gt;
71  * &lt;command name="subscribe-confirm" class="SubscribeConfirm"/&gt;
72  * &lt;command name="unsubscribe" class="UnSubscribe"/&gt;
73  * &lt;command name="unsubscribe-confirm" class="UnSubscribeConfirm"/&gt;
74  * &lt;command name="error" class="ErrorCommand"/&gt;
75  * &lt;command name="owner" class="Owner"/&gt;
76  * &lt;command name="info" class="Info"/&gt;
77  * &lt;/commands&gt;
78  * &lt;/mailet&gt;
79  * </pre>
80  *
81  * <br />
82  * <br />
83  * Todo: refine the command matching so we can have more sophistciated commands such as:
84  * <pre>
85  * &lt;listName&gt;-&lt;commandName&gt;-&lt;optCommandParam&gt;@domain
86  * </pre>
87  *
88  * @version CVS $Revision: 1.1.2.4 $ $Date: 2004/03/30 02:15:24 $
89  * @since 2.2.0
90  */

91 public class CommandListservManager extends GenericMailet implements ICommandListservManager {
92
93     protected Map commandMap = new HashMap();
94     protected List commandPackages = new ArrayList();
95     protected UsersRepository usersRepository;
96     protected String JavaDoc listName;
97     protected String JavaDoc displayName;
98     protected String JavaDoc listOwner;
99     protected String JavaDoc listDomain;
100     protected XMLResources xmlResources;
101
102     /**
103      * Get the name of this list specified by the config param: 'listName'.
104      * <br />
105      * eg: <pre>&lt;listName&gt;announce&lt;/listName&gt;</pre>
106      *
107      * @param displayFormat is whether you want a display version of this or not
108      * @return the official display name of this list
109      */

110     public String JavaDoc getListName(boolean displayFormat) {
111         return displayFormat ? displayName : listName;
112     }
113
114     /**
115      * Gets the owner of this list specified by the config param: 'listOwner'.
116      * <br />
117      * eg: <pre>&lt;listOwner&gt;owner@localhost&lt;/listOwner&gt;</pre>
118      *
119      * @return this is an address like listOwner@localhost
120      */

121     public String JavaDoc getListOwner() {
122         return listOwner;
123     }
124
125     /**
126      * Get the domain of the list specified by the config param: 'listDomain'.
127      * <br />
128      * eg: <pre>&lt;listDomain&gt;localhost&lt;/listDomain&gt;</pre>
129      *
130      * @return a string like localhost
131      */

132     public String JavaDoc getListDomain() {
133         return listDomain;
134     }
135
136     /**
137      * Get a specific command specified by the 'commands' configuration block.
138      * For instance:
139      * <pre>
140      * &lt;commands&gt;
141      * &lt;command name="subscribe" class="Subscribe"/&gt;
142      * &lt;command name="subscribe-confirm" class="SubscribeConfirm"/&gt;
143      * &lt;command name="unsubscribe" class="UnSubscribe"/&gt;
144      * &lt;command name="unsubscribe-confirm" class="UnSubscribeConfirm"/&gt;
145      * &lt;command name="error" class="ErrorCommand"/&gt;
146      * &lt;command name="owner" class="Owner"/&gt;
147      * &lt;command name="info" class="Info"/&gt;
148      * &lt;/commands&gt;
149      * </pre>
150      * @param name case in-sensitive
151      * @return a {@link IListServCommand} if found, null otherwise
152      */

153     public IListServCommand getCommand(String JavaDoc name) {
154         return (IListServCommand) commandMap.get(name.toLowerCase());
155     }
156
157     /**
158      * Get all the available commands
159      * @return a map of {@link IListServCommand}
160      * @see #getCommand
161      */

162     public Map getCommands() {
163         return commandMap;
164     }
165
166     /**
167      * Get the current user repository for this list serv
168      * @return an instance of {@link UsersRepository} that is used for the member list of the list serv
169      */

170     public UsersRepository getUsersRepository() {
171         return usersRepository;
172     }
173
174     /**
175      * An error occurred, send some sort of message
176      * @param subject the subject of the message to send
177      * @param mail
178      * @param errorMessage
179      */

180     public void onError(Mail mail, String JavaDoc subject, String JavaDoc errorMessage) throws MessagingException JavaDoc {
181         ErrorCommand errorCommand = (ErrorCommand) getCommand("error");
182         errorCommand.onError(mail, subject, errorMessage);
183     }
184
185     /**
186      * @return the configuration file for the xml resources
187      */

188     public String JavaDoc getResourcesFile() {
189         return getInitParameter("resources");
190     }
191
192     /**
193      * Use this to get standard properties for future calls to {@link org.apache.james.util.XMLResources}
194      * @return properties with the "LIST_NAME" and the "DOMAIN_NAME" properties
195      */

196     public Properties getStandardProperties() {
197         Properties standardProperties = new Properties();
198         standardProperties.put("LIST_NAME", getListName(false));
199         standardProperties.put("DISPLAY_NAME", getListName(true));
200         standardProperties.put("DOMAIN_NAME", getListDomain());
201         return standardProperties;
202     }
203
204     /**
205      * Initializes an array of resources
206      * @param names such as 'header, footer' etc...
207      * @return an initialized array of XMLResources
208      * @throws ConfigurationException
209      */

210     public XMLResources[] initXMLResources(String JavaDoc[] names) throws ConfigurationException {
211         try {
212             File JavaDoc xmlFile = new File JavaDoc(getResourcesFile());
213
214             Properties props = getStandardProperties();
215             String JavaDoc listName = props.getProperty("LIST_NAME");
216
217             XMLResources[] xmlResources = new XMLResources[names.length];
218             for (int index = 0; index < names.length; index++) {
219                 xmlResources[index] = new XMLResources();
220                 xmlResources[index].init(xmlFile, names[index], listName, props);
221             }
222             return xmlResources;
223         } catch (Exception JavaDoc e) {
224             log(e.getMessage(), e);
225             throw new ConfigurationException("Can't initialize:", e);
226         }
227     }
228
229     public void init() throws MessagingException JavaDoc {
230
231         try {
232             //Well, i want a more complex configuration structure
233
//of my mailet, so i have to cheat... and cheat i will...
234
Configuration configuration = (Configuration) getField(getMailetConfig(), "configuration");
235
236             //get name
237
listName = configuration.getChild("listName").getValue();
238             displayName = configuration.getChild("displayName").getValue();
239             listOwner = configuration.getChild("listOwner").getValue();
240             listDomain = configuration.getChild("listDomain").getValue();
241
242             //initialize resources
243
initializeResources();
244
245             //get users store
246
initUsersRepository();
247
248             //get command packages
249
loadCommandPackages(configuration);
250
251             //load commands
252
loadCommands(configuration);
253
254             //register w/context
255
getMailetContext().setAttribute(ICommandListservManager.ID + listName, this);
256         } catch (Exception JavaDoc e) {
257             throw new MessagingException JavaDoc(e.getMessage(), e);
258         }
259     }
260
261     /**
262      * Based on the to address get a valid or command or null
263      * @param mailAddress
264      * @return IListServCommand or null
265      */

266     public IListServCommand getCommandTarget(MailAddress mailAddress) {
267         String JavaDoc commandName = getCommandName(mailAddress);
268         return getCommand(commandName);
269     }
270
271     /**
272      * <p>Called by the mailet container to allow the mailet to process a
273      * message.</p>
274      *
275      * <p>This method is declared abstract so subclasses must override it.</p>
276      *
277      * @param mail - the Mail object that contains the MimeMessage and
278      * routing information
279      * @throws MessagingException - if an exception occurs that interferes with the mailet's normal operation
280      * occurred
281      */

282     public void service(Mail mail) throws MessagingException JavaDoc {
283         if (mail.getRecipients().size() != 1) {
284             getMailetContext().bounce(mail, "You can only send one command at a time to this listserv manager.");
285             return;
286         }
287         MailAddress mailAddress = (MailAddress) mail.getRecipients().iterator().next();
288         IListServCommand command = getCommandTarget(mailAddress);
289
290         if (command == null) {
291             //don't recognize the command
292
onError(mail,
293                     "unkown command",
294                     xmlResources.getString("command.not.understood", getStandardProperties()));
295         }
296         command.onCommand(mail);
297
298         mail.setState(Mail.GHOST);
299     }
300
301     /**
302      * Get the name of the command
303      * @param mailAddress
304      * @return the name of the command
305      */

306     protected String JavaDoc getCommandName(MailAddress mailAddress) {
307         String JavaDoc user = mailAddress.getUser();
308         int index = user.indexOf('-');
309         String JavaDoc commandName = user.substring(++index);
310         return commandName;
311     }
312
313     /**
314      * initialize the resources
315      * @throws Exception
316      */

317     protected void initializeResources() throws Exception JavaDoc {
318         xmlResources = initXMLResources(new String JavaDoc[]{"List Manager"})[0];
319     }
320
321     /**
322      * Fetch the repository of users
323      */

324     protected void initUsersRepository() {
325         ComponentManager compMgr = (ComponentManager) getMailetContext().getAttribute(Constants.AVALON_COMPONENT_MANAGER);
326         try {
327             UsersStore usersStore = (UsersStore) compMgr.lookup("org.apache.james.services.UsersStore");
328             String JavaDoc repName = getInitParameter("repositoryName");
329
330             usersRepository = usersStore.getRepository(repName);
331         } catch (Exception JavaDoc e) {
332             log("Failed to retrieve Store component:" + e.getMessage());
333         }
334     }
335
336     /**
337      * Load an initialize all of the available commands
338      * @param configuration
339      * @throws ConfigurationException
340      */

341     protected void loadCommands(Configuration configuration) throws Exception JavaDoc {
342         final Configuration commandConfigurations = configuration.getChild("commands");
343         final Configuration[] commandConfs = commandConfigurations.getChildren("command");
344         for (int index = 0; index < commandConfs.length; index++) {
345             Configuration commandConf = commandConfs[index];
346             String JavaDoc commandName = commandConf.getAttribute("name").toLowerCase();
347             String JavaDoc className = commandConf.getAttribute("class");
348             loadCommand(commandName, className, commandConf);
349         }
350     }
351
352     /**
353      * Loads and initializes a single command
354      *
355      * @param commandName
356      * @param className
357      * @param configuration
358      * @throws ConfigurationException
359      */

360     protected void loadCommand(String JavaDoc commandName,
361                                String JavaDoc className,
362                                Configuration configuration)
363             throws ConfigurationException, ClassNotFoundException JavaDoc, IllegalAccessException JavaDoc, InstantiationException JavaDoc {
364         ClassLoader JavaDoc theClassLoader = getClass().getClassLoader();
365         for (Iterator it = commandPackages.iterator(); it.hasNext();) {
366             String JavaDoc packageName = (String JavaDoc) it.next();
367
368             IListServCommand listServCommand = null;
369             try {
370                 listServCommand = (IListServCommand) theClassLoader.loadClass(packageName + className).newInstance();
371             } catch (Exception JavaDoc e) {
372                 //ignore
373
continue;
374             }
375             listServCommand.init(this, configuration);
376             commandMap.put(commandName, listServCommand);
377             return;
378         }
379
380         throw new ConfigurationException("Unable to load listservcommand: " + commandName);
381     }
382
383     /**
384      * loads all of the packages for the commands
385      *
386      * @param configuration
387      * @throws ConfigurationException
388      */

389     protected void loadCommandPackages(Configuration configuration) throws ConfigurationException {
390         commandPackages.add("");
391         final Configuration packageConfiguration = configuration.getChild("commandpackages");
392         final Configuration[] pkgConfs = packageConfiguration.getChildren("commandpackage");
393         for (int index = 0; index < pkgConfs.length; index++) {
394             Configuration conf = pkgConfs[index];
395             String JavaDoc packageName = conf.getValue().trim();
396             if (!packageName.endsWith(".")) {
397                 packageName += ".";
398             }
399             commandPackages.add(packageName);
400         }
401     }
402
403     /**
404      * Retrieves a data field, potentially defined by a super class.
405      * @return null if not found, the object otherwise
406      */

407     protected static Object JavaDoc getField(Object JavaDoc instance, String JavaDoc name) throws IllegalAccessException JavaDoc {
408         Class JavaDoc clazz = instance.getClass();
409         Field JavaDoc[] fields;
410         while (clazz != null) {
411             fields = clazz.getDeclaredFields();
412             for (int index = 0; index < fields.length; index++) {
413                 Field JavaDoc field = fields[index];
414                 if (field.getName().equals(name)) {
415                     field.setAccessible(true);
416                     return field.get(instance);
417                 }
418             }
419             clazz = clazz.getSuperclass();
420         }
421
422         return null;
423     }
424 }
425
Popular Tags