EMMA Coverage Report (generated Mon Aug 23 17:21:34 CEST 2010)
[all classes][org.dcache.cells]

COVERAGE SUMMARY FOR SOURCE FILE [UniversalSpringCell.java]

nameclass, %method, %block, %line, %
UniversalSpringCell.java100% (3/3)47%  (21/45)25%  (444/1750)32%  (111.2/344)

COVERAGE BREAKDOWN BY CLASS AND METHOD

nameclass, %method, %block, %line, %
     
class UniversalSpringCell100% (1/1)38%  (15/39)21%  (342/1641)28%  (88.2/319)
ac_bean_dep (Args): String 0%   (0/1)0%   (0/74)0%   (0/8)
ac_bean_ls (Args): String 0%   (0/1)0%   (0/93)0%   (0/13)
ac_bean_messages_$_0_1 (Args): String 0%   (0/1)0%   (0/167)0%   (0/25)
ac_bean_properties_$_1 (Args): String 0%   (0/1)0%   (0/82)0%   (0/16)
ac_bean_property_$_1 (Args): String 0%   (0/1)0%   (0/22)0%   (0/3)
ac_infox_$_1 (Args): String 0%   (0/1)0%   (0/37)0%   (0/8)
ac_reload (Args): String 0%   (0/1)0%   (0/27)0%   (0/6)
ac_save (Args): String 0%   (0/1)0%   (0/149)0%   (0/32)
addThreadFactoryAwareBean (ThreadFactoryAware): void 0%   (0/1)0%   (0/5)0%   (0/2)
cleanUp (): void 0%   (0/1)0%   (0/35)0%   (0/10)
collectionToString (Collection): String 0%   (0/1)0%   (0/28)0%   (0/6)
firstMissing (File []): File 0%   (0/1)0%   (0/23)0%   (0/4)
getBean (String): Object 0%   (0/1)0%   (0/17)0%   (0/5)
getBeanNames (): List 0%   (0/1)0%   (0/11)0%   (0/3)
getBeanProperty (String): Object 0%   (0/1)0%   (0/38)0%   (0/6)
getCellInfo (): CellInfo 0%   (0/1)0%   (0/22)0%   (0/4)
getDependentBeans (String): List 0%   (0/1)0%   (0/12)0%   (0/3)
getInfo (PrintWriter): void 0%   (0/1)0%   (0/77)0%   (0/16)
getMessageName (Class): String 0%   (0/1)0%   (0/39)0%   (0/7)
invert (Map): Map 0%   (0/1)0%   (0/51)0%   (0/10)
messageArrived (CellMessage): void 0%   (0/1)0%   (0/4)0%   (0/2)
messageToForward (CellMessage): void 0%   (0/1)0%   (0/4)0%   (0/2)
printSetup (PrintWriter): void 0%   (0/1)0%   (0/42)0%   (0/4)
renameWithBackup (File, File): void 0%   (0/1)0%   (0/101)0%   (0/14)
setupCellExecutors (String, String): void 100% (1/1)9%   (5/53)27%  (3/11)
waitForFiles (): void 100% (1/1)14%  (8/57)30%  (3/10)
execFile (File): void 100% (1/1)66%  (45/68)82%  (16.5/20)
executeInit (): void 100% (1/1)85%  (88/103)88%  (16.7/19)
postProcessBeforeInitialization (Object, String): Object 100% (1/1)93%  (54/58)93%  (14/15)
UniversalSpringCell (String, String): void 100% (1/1)100% (40/40)100% (9/9)
access$000 (UniversalSpringCell, Properties, Map): void 100% (1/1)100% (5/5)100% (1/1)
addInfoProviderBean (CellInfoProvider, String): void 100% (1/1)100% (7/7)100% (2/2)
addLifeCycleAwareBean (CellLifeCycleAware): void 100% (1/1)100% (6/6)100% (2/2)
addMessageReceiver (CellMessageReceiver): void 100% (1/1)100% (4/4)100% (2/2)
addMessageSender (CellMessageSender): void 100% (1/1)100% (4/4)100% (2/2)
addSetupProviderBean (CellSetupProvider): void 100% (1/1)100% (6/6)100% (2/2)
executeSetup (): void 100% (1/1)100% (42/42)100% (8/8)
mergeProperties (Properties, Map): void 100% (1/1)100% (26/26)100% (6/6)
postProcessAfterInitialization (Object, String): Object 100% (1/1)100% (2/2)100% (1/1)
     
class UniversalSpringCell$UniversalSpringCellApplicationContext100% (1/1)100% (4/4)93%  (93/100)92%  (22/24)
getDomainContextResource (): ByteArrayResource 100% (1/1)91%  (68/75)88%  (14/16)
UniversalSpringCell$UniversalSpringCellApplicationContext (UniversalSpringCel... 100% (1/1)100% (9/9)100% (3/3)
customizeBeanFactory (DefaultListableBeanFactory): void 100% (1/1)100% (5/5)100% (2/2)
getResource (String): Resource 100% (1/1)100% (11/11)100% (3/3)
     
class UniversalSpringCell$UniversalSpringCellApplicationContext$1100% (1/1)100% (2/2)100% (9/9)100% (2/2)
UniversalSpringCell$UniversalSpringCellApplicationContext$1 (UniversalSpringC... 100% (1/1)100% (7/7)100% (1/1)
getFilename (): String 100% (1/1)100% (2/2)100% (1/1)

1package org.dcache.cells;
2 
3import java.util.Date;
4import java.util.Properties;
5import java.util.Enumeration;
6import java.util.Set;
7import java.util.TreeSet;
8import java.util.Formatter;
9import java.util.ArrayList;
10import java.util.Map;
11import java.util.HashMap;
12import java.util.TreeMap;
13import java.util.List;
14import java.util.Collection;
15import java.util.Collections;
16import java.util.Arrays;
17import java.util.concurrent.ExecutionException;
18import java.util.concurrent.ExecutorService;
19import java.io.ByteArrayOutputStream;
20import java.io.File;
21import java.io.FileWriter;
22import java.io.StringWriter;
23import java.io.PrintWriter;
24import java.io.IOException;
25import java.io.FileReader;
26import java.io.BufferedReader;
27import java.lang.reflect.InvocationTargetException;
28import java.beans.PropertyDescriptor;
29 
30import dmg.cells.nucleus.CellMessage;
31import dmg.cells.nucleus.CellMessageAnswerable;
32import dmg.cells.nucleus.NoRouteToCellException;
33import dmg.cells.nucleus.CellAdapter;
34import dmg.cells.nucleus.CellInfo;
35import dmg.cells.nucleus.CellPath;
36import dmg.cells.services.SetupInfoMessage;
37import dmg.util.Args;
38import dmg.util.CommandException;
39 
40import org.dcache.util.ClassNameComparator;
41 
42import org.springframework.context.ConfigurableApplicationContext;
43import org.springframework.context.support.ClassPathXmlApplicationContext;
44import org.springframework.core.io.ByteArrayResource;
45import org.springframework.core.io.Resource;
46import org.springframework.beans.BeansException;
47import org.springframework.beans.factory.config.BeanPostProcessor;
48import org.springframework.beans.factory.config.BeanDefinition;
49import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
50import org.springframework.beans.factory.support.DefaultListableBeanFactory;
51import org.springframework.beans.factory.NoSuchBeanDefinitionException;
52import org.springframework.beans.BeanWrapper;
53import org.springframework.beans.BeanWrapperImpl;
54 
55/**
56 * Universal cell for building complex cells from simpler components.
57 *
58 * This class aims at being a universal cell for dCache. It makes it
59 * possible to construct complex cells from simpler cell
60 * components. The Spring Framework is used to manage the lifetime of
61 * the cell components, as well as the wiring between components. We
62 * therfore borrow the term "bean" from the Spring Framework and refer
63 * to cell components as beans.
64 *
65 * Beans can get access to core cell functionality by implementing one
66 * or more of the following interfaces: CellInfoProvider,
67 * CellCommunicationAware, ThreadFactoryAware, CellCommandListener,
68 * and CellSetupAware. When instantiated through this class, those
69 * interfaces are detected and the necessary wiring is performed
70 * automatically.
71 */
72public class UniversalSpringCell
73    extends AbstractCell
74    implements BeanPostProcessor
75{
76    private final static long WAIT_FOR_FILE_SLEEP = 30000;
77 
78    /**
79     * Spring application context. All beans are created through this
80     * context.
81     */
82    private ConfigurableApplicationContext _context;
83 
84    /**
85     * Registered info providers mapped to their bean names. Sorted to
86     * maintain consistent ordering.
87     */
88    private final Map<CellInfoProvider,String> _infoProviders =
89        new TreeMap<CellInfoProvider,String>(new ClassNameComparator());
90 
91    /**
92     * List of registered setup providers. Sorted to maintain
93     * consistent ordering.
94     */
95    private final Set<CellSetupProvider> _setupProviders =
96        new TreeSet<CellSetupProvider>(new ClassNameComparator());
97 
98    /**
99     * List of registered life cycle aware beans. Sorted to maintain
100     * consistent ordering.
101     */
102    private final Set<CellLifeCycleAware> _lifeCycleAware =
103        new TreeSet<CellLifeCycleAware>(new ClassNameComparator());
104 
105 
106    /**
107     * Cell name of the setup controller.
108     */
109    private String _setupController;
110 
111    /**
112     * Setup class used for sending a setup to the setup controller.
113     */
114    private String _setupClass;
115 
116    /**
117     * Setup to execute during start and to which to save the setup.
118     */
119    private File _setupFile;
120 
121    public UniversalSpringCell(String cellName, String arguments)
122        throws InterruptedException, ExecutionException
123    {
124        super(cellName, arguments);
125        doInit();
126    }
127 
128    @Override
129    protected void executeInit()
130        throws Exception
131    {
132        /* Process command line arguments.
133         */
134        Args args = getArgs();
135        if (args.argc() == 0)
136            throw new IllegalArgumentException("Configuration location missing");
137 
138        _setupController = args.getOpt("setupController");
139        info("Setup controller set to "
140             + (_setupController == null ? "none" : _setupController));
141        _setupFile =
142            (args.getOpt("setupFile") == null)
143            ? null
144            : new File(args.getOpt("setupFile"));
145        _setupClass = args.getOpt("setupClass");
146 
147        if (_setupController != null && _setupClass == null)
148            throw new IllegalArgumentException("Setup class must be specified when a setup controller is used");
149 
150        /* Instantiate Spring application context. This will
151         * eagerly instantiate all beans.
152         */
153        _context =
154            new UniversalSpringCellApplicationContext(getArgs());
155 
156        /* Cell threading is configurable through arguments to
157         * UniversalSpringCell. The executors have to be created as
158         * beans in the Spring file, however the names of the beans
159         * are provided as cell arguments.
160         */
161        setupCellExecutors(args.getOpt("callbackExecutor"),
162                           args.getOpt("messageExecutor"));
163 
164        /* This is a NOP except if somebody subclassed
165         * UniversalSpringCell.
166         */
167        init();
168 
169        /* The timeout task is essential to handle cell message
170         * timeouts.
171         */
172        startTimeoutTask();
173 
174        /* To ensure that all required file systems are mounted, the
175         * admin may specify some required files. We will block until
176         * they become available.
177         */
178        waitForFiles();
179 
180        /* The setup may be provided as static configuration in the
181         * domain context, as a setup file on disk or through a setup
182         * controller cell.
183         */
184        executeSetup();
185 
186        /* Now that everything is instantiated and configured, we can
187         * start the cell.
188         */
189        start();
190 
191        /* Run the final initialisation hooks.
192         */
193        for (CellLifeCycleAware bean: _lifeCycleAware) {
194            bean.afterStart();
195        }
196    }
197 
198    /**
199     * Closes the application context, which will shutdown all beans.
200     */
201    public void cleanUp()
202    {
203        super.cleanUp();
204        for (CellLifeCycleAware bean: _lifeCycleAware) {
205            bean.beforeStop();
206        }
207        if (_context != null) {
208            _context.close();
209            _context = null;
210        }
211        _infoProviders.clear();
212        _setupProviders.clear();
213        _lifeCycleAware.clear();
214    }
215 
216    private void setupCellExecutors(String callbackExecutor, String messageExecutor)
217    {
218        if (callbackExecutor != null) {
219            Object executor = getBean(callbackExecutor);
220            if (!(executor instanceof ExecutorService)) {
221                throw new IllegalStateException("No such bean: " + callbackExecutor);
222            }
223            getNucleus().setCallbackExecutor((ExecutorService) executor);
224        }
225 
226        if (messageExecutor != null) {
227            Object executor = getBean(messageExecutor);
228            if (!(executor instanceof ExecutorService)) {
229                throw new IllegalStateException("No such bean: " + messageExecutor);
230            }
231            getNucleus().setMessageExecutor((ExecutorService) executor);
232        }
233    }
234 
235    private File firstMissing(File[] files)
236    {
237        for (File file: files) {
238            if (!file.exists()) {
239                return file;
240            }
241        }
242        return null;
243    }
244 
245    private void waitForFiles()
246        throws InterruptedException
247    {
248        String s = getArgs().getOpt("waitForFiles");
249        if (s != null) {
250            String[] paths = s.split(":");
251            File[] files = new File[paths.length];
252            for (int i = 0; i < paths.length; i++) {
253                files[i] = new File(paths[i]);
254            }
255 
256            File missing;
257            while ((missing = firstMissing(files)) != null) {
258                warn(String.format("File missing: %s; sleeping %d seconds", missing, WAIT_FOR_FILE_SLEEP / 1000));
259                Thread.sleep(WAIT_FOR_FILE_SLEEP);
260            }
261        }
262    }
263 
264    private void executeSetup()
265        throws IOException, CommandException
266    {
267        executeDefinedSetup();
268 
269        if( _setupFile != null && _setupFile.isFile() ) {
270            for (CellSetupProvider provider: _setupProviders) {
271                provider.beforeSetup();
272            }
273 
274            execFile(_setupFile);
275 
276            for (CellSetupProvider provider: _setupProviders) {
277                provider.afterSetup();
278            }
279        }
280    }
281 
282    @Override
283    public void messageToForward(CellMessage envelope)
284    {
285        super.messageToForward(envelope);
286    }
287 
288    @Override
289    public void messageArrived(CellMessage envelope)
290    {
291        super.messageArrived(envelope);
292    }
293 
294    /**
295     * Returns the singleton bean with a given name. Returns null if
296     * such a bean does not exist.
297     */
298    private Object getBean(String name)
299    {
300        try {
301            if (_context != null && _context.isSingleton(name)) {
302                return _context.getBean(name);
303            }
304        } catch (NoSuchBeanDefinitionException e) {
305        }
306        return null;
307    }
308 
309    /**
310     * Returns the names of beans that depend of a given bean.
311     */
312    private List<String> getDependentBeans(String name)
313    {
314        if (_context == null) {
315            return Collections.emptyList();
316        } else {
317            return Arrays.asList(_context.getBeanFactory().getDependentBeans(name));
318        }
319    }
320 
321    /**
322     * Returns the collection of singleton bean names.
323     */
324    private List<String> getBeanNames()
325    {
326        if (_context == null) {
327            return Collections.emptyList();
328        } else {
329            return Arrays.asList(_context.getBeanFactory().getSingletonNames());
330        }
331    }
332 
333    /**
334     * Collects information from all registered info providers.
335     */
336    public void getInfo(PrintWriter pw)
337    {
338        ConfigurableListableBeanFactory factory = _context.getBeanFactory();
339        for (Map.Entry<CellInfoProvider,String> entry: _infoProviders.entrySet()) {
340            CellInfoProvider provider = entry.getKey();
341            String name = entry.getValue();
342            try {
343                BeanDefinition definition = factory.getBeanDefinition(name);
344                String description = definition.getDescription();
345                if (description != null) {
346                    pw.println(String.format("--- %s (%s) ---",
347                                             name, description));
348                } else {
349                    pw.println(String.format("--- %s ---", name));
350                }
351                provider.getInfo(pw);
352                pw.println();
353            } catch (NoSuchBeanDefinitionException e) {
354                error("Failed to query bean definition for " + name);
355            }
356        }
357    }
358 
359    /**
360     * Collects information about the cell and returns these in a
361     * CellInfo object. Information is collected from the CellAdapter
362     * base class and from all beans implementing CellInfoProvider.
363     */
364    public CellInfo getCellInfo()
365    {
366        CellInfo info = super.getCellInfo();
367        for (CellInfoProvider provider : _infoProviders.keySet()) {
368            info = provider.getCellInfo(info);
369        }
370        return info;
371    }
372 
373    /**
374     * Collects setup information from all registered setup providers.
375     */
376    protected void printSetup(PrintWriter pw)
377    {
378        pw.println("#\n# Created by " + getCellName() + "("
379                   + getNucleus().getCellClass() + ") at " + (new Date()).toString()
380                   + "\n#");
381        for (CellSetupProvider provider: _setupProviders)
382            provider.printSetup(pw);
383    }
384 
385    public final String hh_save = "[-sc=<setupController>|none] [-file=<filename>] # saves setup to disk or setup controller";
386    public String ac_save(Args args)
387        throws IOException, IllegalArgumentException, NoRouteToCellException
388    {
389        String controller = args.getOpt("sc");
390        String file = args.getOpt("file");
391 
392        if ("none".equals(controller)) {
393            controller = null;
394            file = _setupFile.getPath();
395        } else if (file == null && controller == null) {
396            controller = _setupController;
397            file = _setupFile.getPath();
398        }
399 
400        if (file == null && controller == null) {
401            throw new IllegalArgumentException("Either a setup controller or setup file must be specified");
402        }
403 
404        if (controller != null) {
405            if (_setupClass == null || _setupClass.equals(""))
406                throw new IllegalStateException("Cannot save to a setup controller since the cell has no setup class");
407 
408            try {
409                StringWriter sw = new StringWriter();
410                printSetup(new PrintWriter(sw));
411 
412                SetupInfoMessage info =
413                    new SetupInfoMessage("put", getCellName(),
414                                         _setupClass, sw.toString());
415 
416                sendMessage(new CellMessage(new CellPath(controller), info));
417            } catch (NoRouteToCellException e) {
418                throw new NoRouteToCellException("Failed to send setup to " + controller + ": " + e.getMessage());
419            }
420        }
421 
422        if (file != null) {
423            File path = new File(file).getAbsoluteFile();
424            File directory = path.getParentFile();
425            File temp = File.createTempFile(path.getName(), null, directory);
426            temp.deleteOnExit();
427 
428            PrintWriter pw = new PrintWriter(new FileWriter(temp));
429            try {
430                printSetup(pw);
431            } finally {
432                pw.close();
433            }
434 
435            renameWithBackup(temp, path);
436        }
437 
438        return "";
439    }
440 
441    private static void renameWithBackup(File source, File dest)
442        throws IOException
443    {
444        File backup = new File(dest.getPath() + ".bak");
445 
446        if (dest.exists()) {
447            if (!dest.isFile()) {
448                throw new IOException("Cannot rename " + dest + ": Not a file");
449            }
450            if (backup.exists()) {
451                if (!backup.isFile()) {
452                    throw new IOException("Cannot delete " + backup + ": Not a file");
453                }
454                if (!backup.delete()) {
455                    throw new IOException("Failed to delete " + backup);
456                }
457            }
458            if (!dest.renameTo(backup)) {
459                throw new IOException("Failed to rename " + dest);
460            }
461        }
462        if (!source.renameTo(dest)) {
463            throw new IOException("Failed to rename" + source);
464        }
465    }
466 
467    private void execFile(File setup)
468        throws IOException, CommandException
469    {
470        BufferedReader br = new BufferedReader(new FileReader(setup));
471        String line;
472        try {
473            int lineCount = 0;
474            while ((line = br.readLine()) != null) {
475                ++lineCount;
476 
477                line = line.trim();
478                if (line.length() == 0)
479                    continue;
480                if (line.charAt(0) == '#')
481                    continue;
482                try {
483                    command(new Args(line));
484                } catch (CommandException e) {
485                    throw new CommandException("Error at line " + lineCount
486                                               + ": " + e.getMessage());
487                }
488            }
489        } finally {
490            try {
491                br.close();
492            } catch (IOException e) {
493                // ignored
494            }
495        }
496    }
497 
498    public String hh_reload = "-yes";
499    public String fh_reload =
500        "This command destroys the current setup and replaces it" +
501        "by the setup on disk.";
502    public String ac_reload(Args args)
503        throws IOException, CommandException
504    {
505        if (args.getOpt("yes") == null) {
506            return
507                " This command destroys the current setup\n" +
508                " and replaces it by the setup on disk\n" +
509                " Please use 'reload -yes' if you really want\n" +
510                " to do that.";
511        }
512 
513        if (_setupFile != null && !_setupFile.exists()) {
514            return String.format("Setup file [%s] does not exist", _setupFile);
515        }
516 
517        executeSetup();
518 
519        return "";
520    }
521 
522    /**
523     * Should be renamed to 'info' when command interpreter learns
524     * to handle overloaded commands.
525     */
526    public static final String hh_infox = "<bean>";
527    public String ac_infox_$_1(Args args)
528    {
529        String name = args.argv(0);
530        Object bean = getBean(name);
531        if (CellInfoProvider.class.isInstance(bean)) {
532            StringWriter s = new StringWriter();
533            PrintWriter pw = new PrintWriter(s);
534            ((CellInfoProvider)bean).getInfo(pw);
535            return s.toString();
536        }
537        return "No such bean: " + name;
538    }
539 
540    public static final String hh_bean_ls = "# lists running beans";
541    public String ac_bean_ls(Args args)
542    {
543        final String format = "%-30s %s\n";
544        Formatter s = new Formatter(new StringBuilder());
545        ConfigurableListableBeanFactory factory = _context.getBeanFactory();
546 
547        s.format(format, "Bean", "Description");
548        s.format(format, "----", "-----------");
549        for (String name : getBeanNames()) {
550            try {
551                BeanDefinition definition = factory.getBeanDefinition(name);
552                String description = definition.getDescription();
553                s.format(format, name,
554                         (description != null ? description : "-"));
555            } catch (NoSuchBeanDefinitionException e) {
556                error("Failed to query bean definition for " + name);
557            }
558        }
559        return s.toString();
560    }
561 
562    public static final String hh_bean_dep = "# shows bean dependencies";
563    public String ac_bean_dep(Args args)
564    {
565        final String format = "%-30s %s\n";
566        Formatter s = new Formatter(new StringBuilder());
567        ConfigurableListableBeanFactory factory = _context.getBeanFactory();
568 
569        s.format(format, "Bean", "Used by");
570        s.format(format, "----", "-------");
571        for (String name : getBeanNames()) {
572            s.format(format, name, collectionToString(getDependentBeans(name)));
573        }
574        return s.toString();
575    }
576 
577    /**
578     * If given a simple bean name, returns that bean (equivalent to
579     * calling getBean). If given a compound name using the syntax of
580     * BeanWrapper, then the respective property value is
581     * returned. E.g., getBeanProperty("foo") returns the bean named
582     * "foo", whereas getBeanProperty("foo.bar") returns the value of
583     * the "bar" property of bean "foo".
584     */
585    private Object getBeanProperty(String s)
586    {
587        String[] a = s.split("\\.", 2);
588        Object o = getBean(a[0]);
589        if (o != null && a.length == 2) {
590            BeanWrapper bean = new BeanWrapperImpl(o);
591            o = bean.isReadableProperty(a[1])
592                ? bean.getPropertyValue(a[1])
593                : null;
594        }
595        return o;
596    }
597 
598    public static final String hh_bean_properties =
599        "<bean> # shows properties of a bean";
600    public String ac_bean_properties_$_1(Args args)
601    {
602        String name = args.argv(0);
603        Object o = getBeanProperty(name);
604        if (o != null) {
605            StringBuilder s = new StringBuilder();
606            BeanWrapper bean = new BeanWrapperImpl(o);
607            for (PropertyDescriptor p : bean.getPropertyDescriptors()) {
608                if (!p.isHidden()) {
609                    String property = p.getName();
610                    if (bean.isReadableProperty(property)) {
611                        Object value = bean.getPropertyValue(property);
612                        s.append(property).append('=').append(value);
613                        if (!bean.isWritableProperty(property)) {
614                            s.append(" [read-only]");
615                        }
616                        s.append('\n');
617                    }
618                }
619            }
620            return s.toString();
621        }
622        return "No such bean: " + name;
623    }
624 
625    public static final String hh_bean_property =
626        "<property-name> # shows property of a bean";
627    public String ac_bean_property_$_1(Args args)
628    {
629        String name = args.argv(0);
630        Object o = getBeanProperty(name);
631        return (o != null) ? o.toString() : "No such bean: " + name;
632    }
633 
634    /** Returns a formated name of a message class. */
635    protected String getMessageName(Class c)
636    {
637        String name = c.getSimpleName();
638        int length = name.length();
639        if ((length > 7) && name.endsWith("Message")) {
640            name = name.substring(0, name.length() - 7);
641        } else if ((length > 3) && name.endsWith("Msg")) {
642            name = name.substring(0, name.length() - 3);
643        }
644 
645        return name;
646    }
647 
648    public static final String hh_bean_messages =
649        "[<bean>] # shows message types handled by beans";
650    public String ac_bean_messages_$_0_1(Args args)
651    {
652        switch (args.argc()) {
653        case 0:
654            Map<String,Collection<Class>> map = new HashMap();
655            for (String name: getBeanNames()) {
656                Object bean = getBean(name);
657                if (CellMessageReceiver.class.isInstance(bean)) {
658                    Collection<Class> types =
659                        _messageDispatcher.getMessageTypes(bean);
660                    map.put(name, types);
661                }
662            }
663 
664            final String format = "%-40s %s\n";
665            Formatter f = new Formatter(new StringBuilder());
666            f.format(format, "Message", "Receivers");
667            f.format(format, "-------", "---------");
668            for (Map.Entry<Class,Collection<String>> e: invert(map).entrySet()) {
669                f.format(format,
670                         getMessageName(e.getKey()),
671                         collectionToString(e.getValue()));
672            }
673 
674            return f.toString();
675 
676        case 1:
677            String name = args.argv(0);
678            Object bean = getBean(name);
679            if (CellMessageReceiver.class.isInstance(bean)) {
680                StringBuilder s = new StringBuilder();
681                Collection<Class> types =
682                    _messageDispatcher.getMessageTypes(bean);
683                for (Class t : types) {
684                    s.append(getMessageName(t)).append('\n');
685                }
686                return s.toString();
687            }
688            return "No such bean: " + name;
689 
690        default:
691            return "";
692        }
693    }
694 
695    /**
696     * Registers an info provider. Info providers contribute to the
697     * result of the <code>getInfo</code> method.
698     */
699    public void addInfoProviderBean(CellInfoProvider bean, String name)
700    {
701        _infoProviders.put(bean, name);
702    }
703 
704    /**
705     * Add a message receiver. Message receiver receive messages via
706     * message handlers (see CellMessageDispatcher).
707     */
708    public void addMessageReceiver(CellMessageReceiver bean)
709    {
710        addMessageListener(bean);
711    }
712 
713    /**
714     * Add a message sender. Message senders can send cell messages
715     * via a cell endpoint.
716     */
717    public void addMessageSender(CellMessageSender bean)
718    {
719        bean.setCellEndpoint(this);
720    }
721 
722    /**
723     * Registers a setup provider. Setup providers contribute to the
724     * result of the <code>save</code> method.
725     */
726    public void addSetupProviderBean(CellSetupProvider bean)
727    {
728        _setupProviders.add(bean);
729    }
730 
731    /**
732     * Registers a life cycle aware bean. Life cycle aware beans are
733     * notified about cell start and stop events.
734     */
735    public void addLifeCycleAwareBean(CellLifeCycleAware bean)
736    {
737        _lifeCycleAware.add(bean);
738    }
739 
740    /**
741     * Registers a thread factory aware bean. Thread factory aware
742     * bean provide hooks for registering thread factories. This
743     * method registers the Cell nulceus thread factory on the bean.
744     */
745    public void addThreadFactoryAwareBean(ThreadFactoryAware bean)
746    {
747        bean.setThreadFactory(getNucleus());
748    }
749 
750 
751    /**
752     * Part of the BeanPostProcessor implementation. Recognizes beans
753     * implementing CellCommandListener, CellInfoProvider,
754     * CellCommunicationAware, CellSetupProvider and
755     * ThreadFactoryAware and performs the necessary wiring.
756     */
757    public Object postProcessBeforeInitialization(Object bean,
758                                                  String beanName)
759        throws BeansException
760    {
761        if (CellCommandListener.class.isInstance(bean)) {
762            addCommandListener(bean);
763        }
764 
765        if (CellInfoProvider.class.isInstance(bean)) {
766            addInfoProviderBean((CellInfoProvider)bean, beanName);
767        }
768 
769        if (CellMessageReceiver.class.isInstance(bean)) {
770            addMessageReceiver((CellMessageReceiver)bean);
771        }
772 
773        if (CellMessageSender.class.isInstance(bean)) {
774            addMessageSender((CellMessageSender)bean);
775        }
776 
777        if (CellSetupProvider.class.isInstance(bean)) {
778            addSetupProviderBean((CellSetupProvider)bean);
779        }
780 
781        if (CellLifeCycleAware.class.isInstance(bean)) {
782            addLifeCycleAwareBean((CellLifeCycleAware)bean);
783        }
784 
785        if (ThreadFactoryAware.class.isInstance(bean)) {
786            addThreadFactoryAwareBean((ThreadFactoryAware)bean);
787        }
788        return bean;
789    }
790 
791    public Object postProcessAfterInitialization(Object bean,
792                                                 String beanName)
793        throws BeansException
794    {
795        return bean;
796    }
797 
798    class UniversalSpringCellApplicationContext
799        extends ClassPathXmlApplicationContext
800    {
801        UniversalSpringCellApplicationContext(Args args)
802        {
803            super(args.argv(0));
804        }
805 
806        private ByteArrayResource getDomainContextResource()
807        {
808            Args args = (Args)getArgs().clone();
809            args.shift();
810 
811            Properties properties = new Properties();
812            String arguments =
813                args.toString().replaceAll("-\\$\\{[0-9]+\\}", "");
814            properties.setProperty("arguments", arguments);
815            properties.setProperty("thisCell", getCellName());
816            properties.setProperty("thisDomain", getCellDomainName());
817            mergeProperties(properties, getDomainContext());
818            mergeProperties(properties, args.options());
819 
820            /* Convert to byte array form such that we can make it
821             * available as a Spring resource.
822             */
823            ByteArrayOutputStream out = new ByteArrayOutputStream();
824            try {
825                properties.store(out, "");
826            } catch (IOException e) {
827                /* This should never happen with a ByteArrayOutputStream.
828                 */
829                throw new RuntimeException("Unexpected exception", e);
830            }
831            final byte[] _domainContext = out.toByteArray();
832 
833            return new ByteArrayResource(_domainContext) {
834                /**
835                 * Fake file name to make
836                 * PropertyPlaceholderConfigurer happy.
837                 */
838                public String getFilename()
839                {
840                    return "domaincontext.properties";
841                }
842            };
843        }
844 
845        public Resource getResource(String location)
846        {
847            if (location.startsWith("domaincontext:")) {
848                return getDomainContextResource();
849            } else {
850                return super.getResource(location);
851            }
852        }
853 
854        protected void customizeBeanFactory(DefaultListableBeanFactory beanFactory)
855        {
856            beanFactory.addBeanPostProcessor(UniversalSpringCell.this);
857        }
858    }
859 
860    /**
861     * Utility method for converting a collection of objects to a
862     * string. The string is formed by concatenating the string form
863     * of the objects, separated by a comma.
864     */
865    private <T> String collectionToString(Collection<T> collection)
866    {
867        StringBuilder s = new StringBuilder();
868        for (T o: collection) {
869            if (s.length() > 0) {
870                s.append(',');
871            }
872            s.append(o);
873        }
874        return s.toString();
875    }
876 
877    /**
878     * Merges a map into a property set.
879     */
880    private void mergeProperties(Properties properties, Map<?,?> map)
881    {
882        for (Map.Entry<?,?> e: map.entrySet()) {
883            Object key = e.getKey();
884            Object value = e.getValue();
885            properties.setProperty(key.toString(), value.toString());
886        }
887    }
888 
889    /**
890     * Utility method for inverting a map.
891     *
892     * Given a map { "a" => { 1, 2, 3}, "b" => {2, 3, 4}, c => {3, 4,
893     * 5} }, this method returns a new map { 1 => { "a" }, 2 => { "a",
894     * "b" }, 3 => { "a", "b", "c" }, 4 => { "b", "c" }, 5 => { "c"
895     * }}.
896     *
897     * TODO: Should be moved to a utility library.
898     */
899    private <T1,T2> Map<T1,Collection<T2>> invert(Map<T2,Collection<T1>> map)
900    {
901        Map<T1,Collection<T2>> result = new HashMap();
902        for (Map.Entry<T2,Collection<T1>> e : map.entrySet()) {
903            for (T1 value : e.getValue()) {
904                Collection<T2> collection = result.get(value);
905                if (collection == null) {
906                    collection = new ArrayList<T2>();
907                    result.put(value, collection);
908                }
909                collection.add(e.getKey());
910            }
911        }
912        return result;
913    }
914}

[all classes][org.dcache.cells]
EMMA 2.0.5312 (C) Vladimir Roubtsov