1   /*
2    * SPDX-FileCopyrightText: none
3    * SPDX-License-Identifier: CC0-1.0
4    */
5   
6   package gov.nist.secauto.metaschema.schemagen.xml.impl;
7   
8   import gov.nist.secauto.metaschema.core.datatype.markup.MarkupLine;
9   import gov.nist.secauto.metaschema.core.datatype.markup.MarkupMultiline;
10  import gov.nist.secauto.metaschema.core.model.IDefinition;
11  import gov.nist.secauto.metaschema.core.model.IModelElement;
12  import gov.nist.secauto.metaschema.core.model.INamedInstance;
13  import gov.nist.secauto.metaschema.core.util.CollectionUtil;
14  import gov.nist.secauto.metaschema.schemagen.SchemaGenerationException;
15  import gov.nist.secauto.metaschema.schemagen.xml.XmlSchemaGenerator;
16  
17  import java.util.ArrayList;
18  import java.util.List;
19  
20  import javax.xml.stream.XMLStreamException;
21  
22  import edu.umd.cs.findbugs.annotations.NonNull;
23  import edu.umd.cs.findbugs.annotations.Nullable;
24  
25  public final class DocumentationGenerator {
26  
27    @Nullable
28    private final String formalName;
29    @Nullable
30    private final MarkupLine description;
31    @NonNull
32    private final List<MarkupMultiline> remarks;
33    @NonNull
34    private final IModelElement modelElement;
35  
36    private DocumentationGenerator(@NonNull IDefinition definition) {
37      this.formalName = definition.getEffectiveFormalName();
38      this.description = definition.getEffectiveDescription();
39  
40      MarkupMultiline remarks = definition.getRemarks();
41      this.remarks = remarks == null ? CollectionUtil.emptyList() : CollectionUtil.singletonList(remarks);
42  
43      this.modelElement = definition;
44    }
45  
46    private DocumentationGenerator(@NonNull INamedInstance instance) {
47      this.formalName = instance.getEffectiveFormalName();
48      this.description = instance.getEffectiveDescription();
49  
50      List<MarkupMultiline> remarks = new ArrayList<>(2);
51      MarkupMultiline remark = instance.getRemarks();
52      if (remark != null) {
53        remarks.add(remark);
54      }
55  
56      remark = instance.getDefinition().getRemarks();
57      if (remark != null) {
58        remarks.add(remark);
59      }
60  
61      this.remarks = CollectionUtil.listOrEmpty(remarks);
62  
63      this.modelElement = instance;
64    }
65  
66    @Nullable
67    public String getFormalName() {
68      return formalName;
69    }
70  
71    @Nullable
72    public MarkupLine getDescription() {
73      return description;
74    }
75  
76    @NonNull
77    public List<MarkupMultiline> getRemarks() {
78      return remarks;
79    }
80  
81    @NonNull
82    public IModelElement getModelElement() {
83      return modelElement;
84    }
85  
86    private void generate(@NonNull XmlGenerationState state) {
87      String formalName = getFormalName();
88      MarkupLine description = getDescription();
89      List<MarkupMultiline> remarks = getRemarks();
90  
91      if (formalName != null || description != null || !remarks.isEmpty()) {
92        generateDocumentation(formalName, description, remarks, state.getNS(getModelElement()), state);
93      }
94    }
95  
96    public static void generateDocumentation(
97        @NonNull IDefinition definition,
98        @NonNull XmlGenerationState state) {
99      new DocumentationGenerator(definition).generate(state);
100   }
101 
102   public static void generateDocumentation(
103       @NonNull INamedInstance instance,
104       @NonNull XmlGenerationState state) {
105     new DocumentationGenerator(instance).generate(state);
106   }
107 
108   public static void generateDocumentation( // NOPMD acceptable complexity
109       @Nullable String formalName,
110       @Nullable MarkupLine description,
111       @NonNull List<MarkupMultiline> remarks,
112       @NonNull String xmlNS, @NonNull XmlGenerationState state) {
113 
114     try {
115       state.writeStartElement(XmlSchemaGenerator.PREFIX_XML_SCHEMA, "annotation", XmlSchemaGenerator.NS_XML_SCHEMA);
116       if (formalName != null || description != null) {
117         state.writeStartElement(XmlSchemaGenerator.PREFIX_XML_SCHEMA, "appinfo", XmlSchemaGenerator.NS_XML_SCHEMA);
118 
119         if (formalName != null) {
120           state.writeStartElement(xmlNS, "formal-name");
121           state.writeCharacters(formalName);
122           state.writeEndElement();
123         }
124 
125         if (description != null) {
126           state.writeStartElement(xmlNS, "description");
127           description.writeXHtml(xmlNS, state.getXMLStreamWriter());
128           state.writeEndElement();
129         }
130 
131         state.writeEndElement(); // xs:appInfo
132       }
133 
134       state.writeStartElement(XmlSchemaGenerator.PREFIX_XML_SCHEMA, "documentation", XmlSchemaGenerator.NS_XML_SCHEMA);
135       state.writeNamespace("", XmlSchemaGenerator.NS_XHTML);
136 
137       if (description != null) {
138         // write description
139         state.writeStartElement(XmlSchemaGenerator.NS_XHTML, "p");
140 
141         if (formalName != null) {
142           state.writeStartElement(XmlSchemaGenerator.NS_XHTML, "b");
143           state.writeCharacters(formalName);
144           state.writeEndElement();
145           state.writeCharacters(": ");
146         }
147 
148         description.writeXHtml(XmlSchemaGenerator.NS_XHTML, state.getXMLStreamWriter());
149         state.writeEndElement(); // p
150       }
151 
152       for (MarkupMultiline remark : remarks) {
153         remark.writeXHtml(XmlSchemaGenerator.NS_XHTML, state.getXMLStreamWriter());
154       }
155 
156       state.writeEndElement(); // xs:documentation
157       state.writeEndElement(); // xs:annotation
158     } catch (XMLStreamException ex) {
159       throw new SchemaGenerationException(ex);
160     }
161   }
162 }