View Javadoc
1   /**
2    * Copyright (C) 2014-2015 Philip Helger (www.helger.com)
3    * philip[at]helger[dot]com
4    *
5    * Licensed under the Apache License, Version 2.0 (the "License");
6    * you may not use this file except in compliance with the License.
7    * You may obtain a copy of the License at
8    *
9    *         http://www.apache.org/licenses/LICENSE-2.0
10   *
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the License for the specific language governing permissions and
15   * limitations under the License.
16   */
17  package com.helger.schematron.pure.model;
18  
19  import java.util.ArrayList;
20  import java.util.LinkedHashMap;
21  import java.util.List;
22  import java.util.Map;
23  
24  import javax.annotation.Nonnull;
25  import javax.annotation.Nullable;
26  import javax.annotation.concurrent.NotThreadSafe;
27  
28  import com.helger.commons.ValueEnforcer;
29  import com.helger.commons.annotation.Nonempty;
30  import com.helger.commons.annotation.ReturnsMutableCopy;
31  import com.helger.commons.collection.CollectionHelper;
32  import com.helger.commons.microdom.IMicroElement;
33  import com.helger.commons.microdom.MicroElement;
34  import com.helger.commons.string.StringHelper;
35  import com.helger.commons.string.ToStringGenerator;
36  import com.helger.schematron.CSchematron;
37  import com.helger.schematron.CSchematronXML;
38  import com.helger.schematron.pure.errorhandler.IPSErrorHandler;
39  
40  /**
41   * A single Schematron active-element.<br>
42   * The required pattern attribute is a reference to a pattern that is active in
43   * the current phase.<br>
44   * {@link PSActive} elements are only references from {@link PSPhase} elements.
45   *
46   * @author Philip Helger
47   */
48  @NotThreadSafe
49  public class PSActive implements IPSClonableElement <PSActive>, IPSHasForeignElements, IPSHasMixedContent
50  {
51    private String m_sPattern;
52    private final List <Object> m_aContent = new ArrayList <Object> ();
53    private Map <String, String> m_aForeignAttrs;
54    private List <IMicroElement> m_aForeignElements;
55  
56    public PSActive ()
57    {}
58  
59    public boolean isValid (@Nonnull final IPSErrorHandler aErrorHandler)
60    {
61      for (final Object aContent : m_aContent)
62        if (aContent instanceof IPSElement)
63          if (!((IPSElement) aContent).isValid (aErrorHandler))
64            return false;
65      if (StringHelper.hasNoText (m_sPattern))
66      {
67        aErrorHandler.error (this, "<active> has no 'pattern'");
68        return false;
69      }
70      return true;
71    }
72  
73    public void validateCompletely (@Nonnull final IPSErrorHandler aErrorHandler)
74    {
75      for (final Object aContent : m_aContent)
76        if (aContent instanceof IPSElement)
77          ((IPSElement) aContent).validateCompletely (aErrorHandler);
78      if (StringHelper.hasNoText (m_sPattern))
79        aErrorHandler.error (this, "<active> has no 'pattern'");
80    }
81  
82    public boolean isMinimal ()
83    {
84      for (final Object aContent : m_aContent)
85        if (aContent instanceof IPSElement)
86          if (!((IPSElement) aContent).isMinimal ())
87            return false;
88      return true;
89    }
90  
91    public void addForeignElement (@Nonnull final IMicroElement aForeignElement)
92    {
93      ValueEnforcer.notNull (aForeignElement, "ForeignElement");
94      if (aForeignElement.hasParent ())
95        throw new IllegalArgumentException ("ForeignElement already has a parent!");
96      if (m_aForeignElements == null)
97        m_aForeignElements = new ArrayList <IMicroElement> ();
98      m_aForeignElements.add (aForeignElement);
99    }
100 
101   public void addForeignElements (@Nonnull final List <IMicroElement> aForeignElements)
102   {
103     ValueEnforcer.notNull (aForeignElements, "ForeignElements");
104     for (final IMicroElement aForeignElement : aForeignElements)
105       addForeignElement (aForeignElement);
106   }
107 
108   public boolean hasForeignElements ()
109   {
110     return m_aForeignElements != null && !m_aForeignElements.isEmpty ();
111   }
112 
113   @Nonnull
114   @ReturnsMutableCopy
115   public List <IMicroElement> getAllForeignElements ()
116   {
117     return CollectionHelper.newList (m_aForeignElements);
118   }
119 
120   public void addForeignAttribute (@Nonnull final String sAttrName, @Nonnull final String sAttrValue)
121   {
122     ValueEnforcer.notNull (sAttrName, "AttrName");
123     ValueEnforcer.notNull (sAttrValue, "AttrValue");
124     if (m_aForeignAttrs == null)
125       m_aForeignAttrs = new LinkedHashMap <String, String> ();
126     m_aForeignAttrs.put (sAttrName, sAttrValue);
127   }
128 
129   public void addForeignAttributes (@Nonnull final Map <String, String> aForeignAttrs)
130   {
131     ValueEnforcer.notNull (aForeignAttrs, "ForeignAttrs");
132     for (final Map.Entry <String, String> aEntry : aForeignAttrs.entrySet ())
133       addForeignAttribute (aEntry.getKey (), aEntry.getValue ());
134   }
135 
136   public boolean hasForeignAttributes ()
137   {
138     return m_aForeignAttrs != null && !m_aForeignAttrs.isEmpty ();
139   }
140 
141   @Nonnull
142   @ReturnsMutableCopy
143   public Map <String, String> getAllForeignAttributes ()
144   {
145     return CollectionHelper.newOrderedMap (m_aForeignAttrs);
146   }
147 
148   /**
149    * @param sPattern
150    *        The ID of the pattern to set active.
151    */
152   public void setPattern (@Nullable final String sPattern)
153   {
154     m_sPattern = sPattern;
155   }
156 
157   /**
158    * @return ID of the {@link PSPattern} to be marked active. May be
159    *         <code>null</code>.
160    */
161   @Nullable
162   public String getPattern ()
163   {
164     return m_sPattern;
165   }
166 
167   public void addText (@Nonnull @Nonempty final String sText)
168   {
169     ValueEnforcer.notEmpty (sText, "Text");
170     m_aContent.add (sText);
171   }
172 
173   public boolean hasAnyText ()
174   {
175     for (final Object aElement : m_aContent)
176       if (aElement instanceof String)
177         return true;
178     return false;
179   }
180 
181   @Nonnull
182   @ReturnsMutableCopy
183   public List <String> getAllTexts ()
184   {
185     final List <String> ret = new ArrayList <String> ();
186     for (final Object aElement : m_aContent)
187       if (aElement instanceof String)
188         ret.add ((String) aElement);
189     return ret;
190   }
191 
192   public void addDir (@Nonnull final PSDir aDir)
193   {
194     ValueEnforcer.notNull (aDir, "Dir");
195     m_aContent.add (aDir);
196   }
197 
198   @Nonnull
199   @ReturnsMutableCopy
200   public List <PSDir> getAllDirs ()
201   {
202     final List <PSDir> ret = new ArrayList <PSDir> ();
203     for (final Object aElement : m_aContent)
204       if (aElement instanceof PSDir)
205         ret.add ((PSDir) aElement);
206     return ret;
207   }
208 
209   public void addEmph (@Nonnull final PSEmph aEmph)
210   {
211     ValueEnforcer.notNull (aEmph, "Emph");
212     m_aContent.add (aEmph);
213   }
214 
215   @Nonnull
216   @ReturnsMutableCopy
217   public List <PSEmph> getAllEmphs ()
218   {
219     final List <PSEmph> ret = new ArrayList <PSEmph> ();
220     for (final Object aElement : m_aContent)
221       if (aElement instanceof PSEmph)
222         ret.add ((PSEmph) aElement);
223     return ret;
224   }
225 
226   public void addSpan (@Nonnull final PSSpan aSpan)
227   {
228     ValueEnforcer.notNull (aSpan, "Span");
229     m_aContent.add (aSpan);
230   }
231 
232   @Nonnull
233   @ReturnsMutableCopy
234   public List <PSSpan> getAllSpans ()
235   {
236     final List <PSSpan> ret = new ArrayList <PSSpan> ();
237     for (final Object aElement : m_aContent)
238       if (aElement instanceof PSSpan)
239         ret.add ((PSSpan) aElement);
240     return ret;
241   }
242 
243   /**
244    * @return A list of {@link String}, {@link PSDir}, {@link PSEmph} and
245    *         {@link PSSpan} elements.
246    */
247   @Nonnull
248   @ReturnsMutableCopy
249   public List <Object> getAllContentElements ()
250   {
251     return CollectionHelper.newList (m_aContent);
252   }
253 
254   @Nonnull
255   public IMicroElement getAsMicroElement ()
256   {
257     final IMicroElement ret = new MicroElement (CSchematron.NAMESPACE_SCHEMATRON, CSchematronXML.ELEMENT_ACTIVE);
258     ret.setAttribute (CSchematronXML.ATTR_PATTERN, m_sPattern);
259     if (m_aForeignElements != null)
260       for (final IMicroElement aForeignElement : m_aForeignElements)
261         ret.appendChild (aForeignElement.getClone ());
262     for (final Object aContent : m_aContent)
263       if (aContent instanceof String)
264         ret.appendText ((String) aContent);
265       else
266         ret.appendChild (((IPSElement) aContent).getAsMicroElement ());
267     if (m_aForeignAttrs != null)
268       for (final Map.Entry <String, String> aEntry : m_aForeignAttrs.entrySet ())
269         ret.setAttribute (aEntry.getKey (), aEntry.getValue ());
270     return ret;
271   }
272 
273   @Nonnull
274   public PSActive getClone ()
275   {
276     final PSActive ret = new PSActive ();
277     ret.setPattern (m_sPattern);
278     for (final Object aContent : m_aContent)
279     {
280       if (aContent instanceof String)
281         ret.addText ((String) aContent);
282       else
283         if (aContent instanceof PSDir)
284           ret.addDir (((PSDir) aContent).getClone ());
285         else
286           if (aContent instanceof PSEmph)
287             ret.addEmph (((PSEmph) aContent).getClone ());
288           else
289             if (aContent instanceof PSSpan)
290               ret.addSpan (((PSSpan) aContent).getClone ());
291     }
292     if (hasForeignElements ())
293       ret.addForeignElements (m_aForeignElements);
294     if (hasForeignAttributes ())
295       ret.addForeignAttributes (m_aForeignAttrs);
296     return ret;
297   }
298 
299   @Override
300   public String toString ()
301   {
302     return new ToStringGenerator (this).appendIfNotNull ("pattern", m_sPattern)
303                                        .appendIfNotEmpty ("content", m_aContent)
304                                        .appendIfNotEmpty ("foreignAttrs", m_aForeignAttrs)
305                                        .appendIfNotEmpty ("foreignElements", m_aForeignElements)
306                                        .toString ();
307   }
308 }