001// Copyright 2004, 2005 The Apache Software Foundation
002//
003// Licensed under the Apache License, Version 2.0 (the "License");
004// you may not use this file except in compliance with the License.
005// You may obtain a copy of the License at
006//
007//     http://www.apache.org/licenses/LICENSE-2.0
008//
009// Unless required by applicable law or agreed to in writing, software
010// distributed under the License is distributed on an "AS IS" BASIS,
011// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
012// See the License for the specific language governing permissions and
013// limitations under the License.
014
015package org.apache.hivemind.ant;
016
017import java.util.ArrayList;
018import java.util.Collection;
019import java.util.HashSet;
020import java.util.Iterator;
021import java.util.List;
022import java.util.Set;
023
024import javax.xml.parsers.DocumentBuilder;
025import javax.xml.parsers.DocumentBuilderFactory;
026import javax.xml.parsers.ParserConfigurationException;
027
028import org.apache.hivemind.ApplicationRuntimeException;
029import org.apache.hivemind.Attribute;
030import org.apache.hivemind.ClassResolver;
031import org.apache.hivemind.ErrorHandler;
032import org.apache.hivemind.ModuleDescriptorProvider;
033import org.apache.hivemind.Occurances;
034import org.apache.hivemind.impl.DefaultClassResolver;
035import org.apache.hivemind.impl.DefaultErrorHandler;
036import org.apache.hivemind.impl.XmlModuleDescriptorProvider;
037import org.apache.hivemind.internal.Visibility;
038import org.apache.hivemind.parse.AttributeMappingDescriptor;
039import org.apache.hivemind.parse.ConfigurationPointDescriptor;
040import org.apache.hivemind.parse.ContributionDescriptor;
041import org.apache.hivemind.parse.ConversionDescriptor;
042import org.apache.hivemind.parse.CreateInstanceDescriptor;
043import org.apache.hivemind.parse.DependencyDescriptor;
044import org.apache.hivemind.parse.ImplementationDescriptor;
045import org.apache.hivemind.parse.InstanceBuilder;
046import org.apache.hivemind.parse.InterceptorDescriptor;
047import org.apache.hivemind.parse.InvokeFactoryDescriptor;
048import org.apache.hivemind.parse.ModuleDescriptor;
049import org.apache.hivemind.parse.ServicePointDescriptor;
050import org.apache.hivemind.parse.SubModuleDescriptor;
051import org.apache.hivemind.schema.AttributeModel;
052import org.apache.hivemind.schema.ElementModel;
053import org.apache.hivemind.schema.Rule;
054import org.apache.hivemind.schema.impl.SchemaImpl;
055import org.apache.hivemind.schema.rules.CreateObjectRule;
056import org.apache.hivemind.schema.rules.InvokeParentRule;
057import org.apache.hivemind.schema.rules.PushAttributeRule;
058import org.apache.hivemind.schema.rules.PushContentRule;
059import org.apache.hivemind.schema.rules.ReadAttributeRule;
060import org.apache.hivemind.schema.rules.ReadContentRule;
061import org.apache.hivemind.schema.rules.SetModuleRule;
062import org.apache.hivemind.schema.rules.SetParentRule;
063import org.apache.hivemind.schema.rules.SetPropertyRule;
064import org.apache.hivemind.util.IdUtils;
065import org.w3c.dom.Document;
066import org.w3c.dom.Element;
067
068/**
069 * This class serializes a set of {@link ModuleDescriptor module descriptors} into a
070 * {@link Document XML document}. The set of module descriptors to process is specified indirectly
071 * by supplying one or several {@link ModuleDescriptorProvider} (see
072 * {@link #addModuleDescriptorProvider(ModuleDescriptorProvider)}). In this respect this class is
073 * used the same way as {@link org.apache.hivemind.impl.RegistryBuilder}. There is even a
074 * corresponding {@link #createDefaultRegistryDocument() static method} to serialize the modules of
075 * the default registry.
076 * <p>
077 * The resulting XML file does not conform to the hivemind module deployment descriptor schema. The
078 * following changes occur:
079 * <ul>
080 * <li>The outermost element is &lt;registry&gt; (which contains a list of &lt;module&gt;)
081 * <li>A unique id (unique within the file) is assigned to each &lt;module&gt;,
082 * &lt;configuration-point&gt;, &lt;service-point&gt;, &lt;contribution&gt;, &tl;schema&gt; and
083 * &lt;implementation&gt; (this is to make it easier to generate links and anchors)
084 * <li>Unqualified ids are converted to qualified ids (whereever possible).
085 * </ul>
086 * 
087 * @author Knut Wannheden
088 * @since 1.1
089 */
090public class RegistrySerializer
091{
092    private Set _processedSchemas = new HashSet();
093
094    private List _providers = new ArrayList();
095
096    private ErrorHandler _handler;
097
098    private Document _document;
099
100    private ModuleDescriptor _md;
101
102    public RegistrySerializer()
103    {
104        _handler = new DefaultErrorHandler();
105    }
106
107    public void addModuleDescriptorProvider(ModuleDescriptorProvider provider)
108    {
109        _providers.add(provider);
110    }
111
112    public Document createRegistryDocument()
113    {
114        DocumentBuilder builder = getBuilder();
115
116        _document = builder.newDocument();
117
118        Element registry = _document.createElement("registry");
119
120        _document.appendChild(registry);
121
122        for (Iterator i = _providers.iterator(); i.hasNext();)
123        {
124            ModuleDescriptorProvider provider = (ModuleDescriptorProvider) i.next();
125
126            processModuleDescriptorProvider(registry, provider);
127        }
128
129        return _document;
130    }
131
132    private void processModuleDescriptorProvider(Element registry, ModuleDescriptorProvider provider)
133    {
134        for (Iterator j = provider.getModuleDescriptors(_handler).iterator(); j.hasNext();)
135        {
136            _md = (ModuleDescriptor) j.next();
137
138            Element module = getModuleElement(_md);
139
140            registry.appendChild(module);
141        }
142    }
143
144    private Element getModuleElement(ModuleDescriptor md)
145    {
146        Element module = _document.createElement("module");
147
148        module.setAttribute("id", md.getModuleId());
149        module.setAttribute("version", md.getVersion());
150        module.setAttribute("package", md.getPackageName());
151
152        module.appendChild(_document.createTextNode(md.getAnnotation()));
153
154        addDependencies(module);
155
156        addServicePoints(module);
157
158        addConfigurationPoints(module);
159
160        addContributions(module);
161
162        addImplementations(module);
163
164        addSchemas(module);
165
166        addSubModules(module);
167
168        return module;
169    }
170
171    private void addDependencies(Element module)
172    {
173        List dependencies = _md.getDependencies();
174
175        if (dependencies != null)
176        {
177            for (Iterator i = dependencies.iterator(); i.hasNext();)
178            {
179                DependencyDescriptor dd = (DependencyDescriptor) i.next();
180
181                Element dependency = getDependencyElement(dd);
182
183                module.appendChild(dependency);
184            }
185        }
186    }
187
188    private void addServicePoints(Element module)
189    {
190        List servicePoints = _md.getServicePoints();
191
192        if (servicePoints != null)
193        {
194            for (Iterator i = servicePoints.iterator(); i.hasNext();)
195            {
196                ServicePointDescriptor spd = (ServicePointDescriptor) i.next();
197
198                Element servicePoint = getServicePointElement(spd);
199
200                module.appendChild(servicePoint);
201
202                SchemaImpl s = (SchemaImpl) spd.getParametersSchema();
203
204                if (s != null && s.getId() != null)
205                    addSchema(module, s, "schema");
206            }
207        }
208    }
209
210    private void addConfigurationPoints(Element module)
211    {
212        List configurationPoints = _md.getConfigurationPoints();
213
214        if (configurationPoints != null)
215        {
216            for (Iterator i = configurationPoints.iterator(); i.hasNext();)
217            {
218                ConfigurationPointDescriptor cpd = (ConfigurationPointDescriptor) i.next();
219
220                Element configurationPoint = getConfigurationPointElement(cpd);
221
222                module.appendChild(configurationPoint);
223
224                SchemaImpl s = (SchemaImpl) cpd.getContributionsSchema();
225
226                if (s != null && s.getId() != null)
227                    addSchema(module, s, "schema");
228            }
229        }
230    }
231
232    private void addContributions(Element module)
233    {
234        List contributions = _md.getContributions();
235
236        if (contributions != null)
237        {
238            for (Iterator i = contributions.iterator(); i.hasNext();)
239            {
240                ContributionDescriptor cd = (ContributionDescriptor) i.next();
241
242                Element contribution = getContributionElement(cd);
243
244                module.appendChild(contribution);
245            }
246        }
247    }
248
249    private void addImplementations(Element module)
250    {
251        List implementations = _md.getImplementations();
252
253        if (implementations != null)
254        {
255            for (Iterator i = implementations.iterator(); i.hasNext();)
256            {
257                ImplementationDescriptor id = (ImplementationDescriptor) i.next();
258
259                Element implementation = getImplementationElement(id);
260
261                module.appendChild(implementation);
262            }
263        }
264    }
265
266    private void addSchemas(Element module)
267    {
268        Collection schemas = _md.getSchemas();
269
270        for (Iterator i = schemas.iterator(); i.hasNext();)
271        {
272            SchemaImpl s = (SchemaImpl) i.next();
273
274            addSchema(module, s, "schema");
275        }
276    }
277
278    private void addSubModules(Element module)
279    {
280        List subModules = _md.getSubModules();
281
282        if (subModules != null)
283        {
284            for (Iterator i = subModules.iterator(); i.hasNext();)
285            {
286                SubModuleDescriptor smd = (SubModuleDescriptor) i.next();
287
288                Element subModule = getSubModuleElement(smd);
289
290                module.appendChild(subModule);
291            }
292        }
293    }
294
295    private Element getDependencyElement(DependencyDescriptor dd)
296    {
297        Element dependency = _document.createElement("dependency");
298
299        dependency.setAttribute("module-id", dd.getModuleId());
300        dependency.setAttribute("version", dd.getVersion());
301
302        return dependency;
303    }
304
305    private Element getServicePointElement(ServicePointDescriptor spd)
306    {
307        Element servicePoint = _document.createElement("service-point");
308
309        servicePoint.setAttribute("id", qualify(spd.getId()));
310        servicePoint.setAttribute("interface", spd.getInterfaceClassName());
311        if (spd.getVisibility() == Visibility.PRIVATE)
312            servicePoint.setAttribute("visibility", "private");
313        if (spd.getParametersCount() != Occurances.REQUIRED)
314            servicePoint.setAttribute("parameters-occurs", spd.getParametersCount().getName()
315                    .toLowerCase());
316
317        servicePoint.appendChild(_document.createTextNode(spd.getAnnotation()));
318
319        if (spd.getParametersSchema() != null)
320            addSchema(servicePoint, (SchemaImpl) spd.getParametersSchema(), "parameters-schema");
321        else if (spd.getParametersSchemaId() != null)
322            servicePoint.setAttribute("parameters-schema-id", qualify(spd.getParametersSchemaId()));
323
324        InstanceBuilder ib = spd.getInstanceBuilder();
325
326        if (ib != null)
327        {
328            Element instanceBuilder = getInstanceBuilderElement(ib);
329
330            servicePoint.appendChild(instanceBuilder);
331        }
332
333        List interceptors = spd.getInterceptors();
334
335        if (interceptors != null)
336        {
337            for (Iterator i = interceptors.iterator(); i.hasNext();)
338            {
339                InterceptorDescriptor icd = (InterceptorDescriptor) i.next();
340
341                Element interceptor = getInterceptorElement(icd);
342
343                servicePoint.appendChild(interceptor);
344            }
345        }
346
347        return servicePoint;
348    }
349
350    private Element getConfigurationPointElement(ConfigurationPointDescriptor cpd)
351    {
352        Element configurationPoint = _document.createElement("configuration-point");
353
354        configurationPoint.setAttribute("id", qualify(cpd.getId()));
355        if (cpd.getVisibility() == Visibility.PRIVATE)
356            configurationPoint.setAttribute("visibility", "private");
357
358        configurationPoint.appendChild(_document.createTextNode(cpd.getAnnotation()));
359
360        if (cpd.getContributionsSchema() != null)
361            addSchema(configurationPoint, (SchemaImpl) cpd.getContributionsSchema(), "schema");
362        else if (cpd.getContributionsSchemaId() != null)
363            configurationPoint.setAttribute("schema-id", qualify(cpd.getContributionsSchemaId()));
364
365        return configurationPoint;
366    }
367
368    private Element getContributionElement(ContributionDescriptor cd)
369    {
370        Element contribution = _document.createElement("contribution");
371
372        contribution.setAttribute("configuration-id", qualify(cd.getConfigurationId()));
373
374        if (cd.getConditionalExpression() != null)
375            contribution.setAttribute("if", cd.getConditionalExpression());
376
377        List parameters = cd.getElements();
378
379        if (parameters != null)
380        {
381            for (Iterator i = parameters.iterator(); i.hasNext();)
382            {
383                org.apache.hivemind.Element parameter = (org.apache.hivemind.Element) i.next();
384
385                Element element = getParamterElement(parameter);
386
387                contribution.appendChild(element);
388            }
389        }
390
391        contribution.appendChild(_document.createTextNode(cd.getAnnotation()));
392
393        return contribution;
394    }
395
396    private Element getImplementationElement(ImplementationDescriptor id)
397    {
398        Element implementation = _document.createElement("implementation");
399
400        implementation.setAttribute("service-id", qualify(id.getServiceId()));
401
402        if (id.getConditionalExpression() != null)
403            implementation.setAttribute("if", id.getConditionalExpression());
404
405        implementation.appendChild(_document.createTextNode(id.getAnnotation()));
406
407        InstanceBuilder ib = id.getInstanceBuilder();
408
409        if (ib != null)
410        {
411            Element instanceBuilder = getInstanceBuilderElement(ib);
412
413            implementation.appendChild(instanceBuilder);
414        }
415
416        List interceptors = id.getInterceptors();
417
418        if (interceptors != null)
419        {
420            for (Iterator i = interceptors.iterator(); i.hasNext();)
421            {
422                InterceptorDescriptor icd = (InterceptorDescriptor) i.next();
423
424                Element interceptor = getInterceptorElement(icd);
425
426                implementation.appendChild(interceptor);
427            }
428        }
429
430        return implementation;
431    }
432
433    private Element getSubModuleElement(SubModuleDescriptor smd)
434    {
435        Element subModule = _document.createElement("sub-module");
436
437        subModule.setAttribute("descriptor", smd.getDescriptor().getPath());
438
439        return subModule;
440    }
441
442    private Element getInstanceBuilderElement(InstanceBuilder ib)
443    {
444        Element instanceBuilder;
445
446        if (ib instanceof CreateInstanceDescriptor)
447        {
448            CreateInstanceDescriptor cid = (CreateInstanceDescriptor) ib;
449            instanceBuilder = _document.createElement("create-instance");
450
451            instanceBuilder.setAttribute("class", cid.getInstanceClassName());
452            if (!cid.getServiceModel().equals("singleton"))
453                instanceBuilder.setAttribute("model", cid.getServiceModel());
454        }
455        else
456        {
457            InvokeFactoryDescriptor ifd = (InvokeFactoryDescriptor) ib;
458            instanceBuilder = _document.createElement("invoke-factory");
459
460            if (!ifd.getFactoryServiceId().equals("hivemind.BuilderFactory"))
461                instanceBuilder.setAttribute("service-id", qualify(ifd.getFactoryServiceId()));
462            if (ifd.getServiceModel() != null)
463                instanceBuilder.setAttribute("model", ifd.getServiceModel());
464
465            List parameters = ifd.getParameters();
466
467            if (parameters != null)
468            {
469                for (Iterator i = parameters.iterator(); i.hasNext();)
470                {
471                    org.apache.hivemind.Element parameter = (org.apache.hivemind.Element) i.next();
472
473                    Element element = getParamterElement(parameter);
474
475                    instanceBuilder.appendChild(element);
476                }
477            }
478        }
479
480        return instanceBuilder;
481    }
482
483    private Element getInterceptorElement(InterceptorDescriptor icd)
484    {
485        Element interceptor = _document.createElement("interceptor");
486
487        interceptor.setAttribute("service-id", qualify(icd.getFactoryServiceId()));
488        if (icd.getBefore() != null)
489            interceptor.setAttribute("before", icd.getBefore());
490        if (icd.getAfter() != null)
491            interceptor.setAttribute("after", icd.getAfter());
492        return interceptor;
493    }
494
495    private Element getParamterElement(org.apache.hivemind.Element parameter)
496    {
497        Element element = _document.createElement(parameter.getElementName());
498
499        List attributes = parameter.getAttributes();
500
501        for (Iterator i = attributes.iterator(); i.hasNext();)
502        {
503            Attribute attribute = (Attribute) i.next();
504
505            element.setAttribute(attribute.getName(), attribute.getValue());
506        }
507
508        List elements = parameter.getElements();
509
510        for (Iterator i = elements.iterator(); i.hasNext();)
511        {
512            org.apache.hivemind.Element nestedParameter = (org.apache.hivemind.Element) i.next();
513
514            element.appendChild(getParamterElement(nestedParameter));
515        }
516
517        return element;
518    }
519
520    private void addSchema(Element container, SchemaImpl s, String elementName)
521    {
522        if (_processedSchemas.contains(s))
523            return;
524
525        Element schema = _document.createElement(elementName);
526
527        if (s.getId() != null)
528            schema.setAttribute("id", qualify(s.getId()));
529
530        if (s.getVisibility() == Visibility.PRIVATE)
531            schema.setAttribute("visibility", "private");
532
533        schema.appendChild(_document.createTextNode(s.getAnnotation()));
534
535        for (Iterator j = s.getElementModel().iterator(); j.hasNext();)
536        {
537            ElementModel em = (ElementModel) j.next();
538
539            Element element = getElementElement(em);
540
541            schema.appendChild(element);
542        }
543
544        container.appendChild(schema);
545
546        _processedSchemas.add(s);
547    }
548
549    private Element getRulesElement(ElementModel em)
550    {
551        Element rules = _document.createElement("rules");
552
553        for (Iterator i = em.getRules().iterator(); i.hasNext();)
554        {
555            Rule r = (Rule) i.next();
556
557            Element rule = null;
558
559            if (r instanceof CreateObjectRule)
560            {
561                CreateObjectRule cor = (CreateObjectRule) r;
562                rule = _document.createElement("create-object");
563
564                rule.setAttribute("class", cor.getClassName());
565            }
566            else if (r instanceof InvokeParentRule)
567            {
568                InvokeParentRule ipr = (InvokeParentRule) r;
569                rule = _document.createElement("invoke-parent");
570
571                rule.setAttribute("method", ipr.getMethodName());
572                if (ipr.getDepth() != 1)
573                    rule.setAttribute("depth", Integer.toString(ipr.getDepth()));
574            }
575            else if (r instanceof PushAttributeRule)
576            {
577                PushAttributeRule par = (PushAttributeRule) r;
578                rule = _document.createElement("push-attribute");
579
580                rule.setAttribute("attribute", par.getAttributeName());
581            }
582            else if (r instanceof PushContentRule)
583            {              
584                rule = _document.createElement("push-content");
585            }
586            else if (r instanceof ReadAttributeRule)
587            {
588                ReadAttributeRule rar = (ReadAttributeRule) r;
589                rule = _document.createElement("read-attribute");
590
591                rule.setAttribute("property", rar.getPropertyName());
592                rule.setAttribute("attribute", rar.getAttributeName());
593                if (!rar.getSkipIfNull())
594                    rule.setAttribute("skip-if-null", "false");
595                if (rar.getTranslator() != null)
596                    rule.setAttribute("translator", rar.getTranslator());
597            }
598            else if (r instanceof ReadContentRule)
599            {
600                ReadContentRule rcr = (ReadContentRule) r;
601                rule = _document.createElement("read-content");
602
603                rule.setAttribute("property", rcr.getPropertyName());
604            }
605            else if (r instanceof SetModuleRule)
606            {
607                SetModuleRule smr = (SetModuleRule) r;
608                rule = _document.createElement("set-module");
609
610                rule.setAttribute("property", smr.getPropertyName());
611            }
612            else if (r instanceof SetParentRule)
613            {
614                SetParentRule spr = (SetParentRule) r;
615                rule = _document.createElement("set-parent");
616
617                rule.setAttribute("property", spr.getPropertyName());
618            }
619            else if (r instanceof SetPropertyRule)
620            {
621                SetPropertyRule spr = (SetPropertyRule) r;
622                rule = _document.createElement("set-property");
623
624                rule.setAttribute("property", spr.getPropertyName());
625                rule.setAttribute("value", spr.getValue());
626            }
627            else if (r instanceof ConversionDescriptor)
628            {
629                ConversionDescriptor cd = (ConversionDescriptor) r;
630                rule = _document.createElement("conversion");
631
632                rule.setAttribute("class", cd.getClassName());
633                if (!cd.getParentMethodName().equals("addElement"))
634                    rule.setAttribute("parent-method", cd.getParentMethodName());
635
636                for (Iterator j = cd.getAttributeMappings().iterator(); j.hasNext();)
637                {
638                    AttributeMappingDescriptor amd = (AttributeMappingDescriptor) j.next();
639
640                    Element map = _document.createElement("map");
641
642                    map.setAttribute("attribute", amd.getAttributeName());
643                    map.setAttribute("property", amd.getPropertyName());
644
645                    rule.appendChild(map);
646                }
647            }
648            else
649            {
650                rule = _document.createElement("custom");
651
652                rule.setAttribute("class", r.getClass().getName());
653            }
654
655            if (rule != null)
656                rules.appendChild(rule);
657        }
658        return rules;
659    }
660
661    private Element getElementElement(ElementModel em)
662    {
663        Element element = _document.createElement("element");
664        element.setAttribute("name", em.getElementName());
665
666        element.appendChild(_document.createTextNode(em.getAnnotation()));
667
668        for (Iterator i = em.getAttributeModels().iterator(); i.hasNext();)
669        {
670            AttributeModel am = (AttributeModel) i.next();
671
672            Element attribute = getAttributeElement(am);
673
674            element.appendChild(attribute);
675        }
676
677        for (Iterator i = em.getElementModel().iterator(); i.hasNext();)
678        {
679            ElementModel nestedEm = (ElementModel) i.next();
680
681            Element nestedElement = getElementElement(nestedEm);
682
683            element.appendChild(nestedElement);
684        }
685
686        if (!em.getRules().isEmpty())
687        {
688            Element rules = getRulesElement(em);
689
690            element.appendChild(rules);
691        }
692
693        return element;
694    }
695
696    private Element getAttributeElement(AttributeModel am)
697    {
698        Element attribute = _document.createElement("attribute");
699
700        attribute.setAttribute("name", am.getName());
701        if (am.isRequired())
702            attribute.setAttribute("required", "true");
703        if (am.isUnique())
704            attribute.setAttribute("unique", "true");
705        if (!am.getTranslator().equals("smart"))
706            attribute.setAttribute("translator", am.getTranslator());
707
708        attribute.appendChild(_document.createTextNode(am.getAnnotation()));
709
710        return attribute;
711    }
712
713    private String qualify(String id)
714    {
715        return IdUtils.qualify(_md.getModuleId(), id);
716    }
717
718    private DocumentBuilder getBuilder()
719    {
720        DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
721
722        factory.setIgnoringComments(true);
723
724        try
725        {
726            return factory.newDocumentBuilder();
727        }
728        catch (ParserConfigurationException e)
729        {
730            throw new ApplicationRuntimeException(e);
731        }
732    }
733
734    public static Document createDefaultRegistryDocument()
735    {
736        ClassResolver resolver = new DefaultClassResolver();
737        ModuleDescriptorProvider provider = new XmlModuleDescriptorProvider(resolver);
738
739        RegistrySerializer serializer = new RegistrySerializer();
740
741        serializer.addModuleDescriptorProvider(provider);
742
743        return serializer.createRegistryDocument();
744    }
745}