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    
015    package org.apache.hivemind.ant;
016    
017    import java.util.ArrayList;
018    import java.util.Collection;
019    import java.util.HashSet;
020    import java.util.Iterator;
021    import java.util.List;
022    import java.util.Set;
023    
024    import javax.xml.parsers.DocumentBuilder;
025    import javax.xml.parsers.DocumentBuilderFactory;
026    import javax.xml.parsers.ParserConfigurationException;
027    
028    import org.apache.hivemind.ApplicationRuntimeException;
029    import org.apache.hivemind.Attribute;
030    import org.apache.hivemind.ClassResolver;
031    import org.apache.hivemind.ErrorHandler;
032    import org.apache.hivemind.ModuleDescriptorProvider;
033    import org.apache.hivemind.Occurances;
034    import org.apache.hivemind.impl.DefaultClassResolver;
035    import org.apache.hivemind.impl.DefaultErrorHandler;
036    import org.apache.hivemind.impl.XmlModuleDescriptorProvider;
037    import org.apache.hivemind.internal.Visibility;
038    import org.apache.hivemind.parse.AttributeMappingDescriptor;
039    import org.apache.hivemind.parse.ConfigurationPointDescriptor;
040    import org.apache.hivemind.parse.ContributionDescriptor;
041    import org.apache.hivemind.parse.ConversionDescriptor;
042    import org.apache.hivemind.parse.CreateInstanceDescriptor;
043    import org.apache.hivemind.parse.DependencyDescriptor;
044    import org.apache.hivemind.parse.ImplementationDescriptor;
045    import org.apache.hivemind.parse.InstanceBuilder;
046    import org.apache.hivemind.parse.InterceptorDescriptor;
047    import org.apache.hivemind.parse.InvokeFactoryDescriptor;
048    import org.apache.hivemind.parse.ModuleDescriptor;
049    import org.apache.hivemind.parse.ServicePointDescriptor;
050    import org.apache.hivemind.parse.SubModuleDescriptor;
051    import org.apache.hivemind.schema.AttributeModel;
052    import org.apache.hivemind.schema.ElementModel;
053    import org.apache.hivemind.schema.Rule;
054    import org.apache.hivemind.schema.impl.SchemaImpl;
055    import org.apache.hivemind.schema.rules.CreateObjectRule;
056    import org.apache.hivemind.schema.rules.InvokeParentRule;
057    import org.apache.hivemind.schema.rules.PushAttributeRule;
058    import org.apache.hivemind.schema.rules.PushContentRule;
059    import org.apache.hivemind.schema.rules.ReadAttributeRule;
060    import org.apache.hivemind.schema.rules.ReadContentRule;
061    import org.apache.hivemind.schema.rules.SetModuleRule;
062    import org.apache.hivemind.schema.rules.SetParentRule;
063    import org.apache.hivemind.schema.rules.SetPropertyRule;
064    import org.apache.hivemind.util.IdUtils;
065    import org.w3c.dom.Document;
066    import 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     */
090    public 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    }