1
2
3
4
5
6
7
8
9
10
11
12 package sk.uniba.euromath.document;
13 import java.io.IOException;
14 import java.io.OutputStream;
15 import java.net.URL;
16 import java.util.HashSet;
17 import java.util.Map;
18 import java.util.Set;
19 import java.util.WeakHashMap;
20 import org.w3c.dom.Document;
21 import org.w3c.dom.Element;
22 import org.w3c.dom.ls.DOMImplementationLS;
23 import org.w3c.dom.ls.LSOutput;
24 import org.w3c.dom.ls.LSSerializer;
25 import org.w3c.dom.traversal.DocumentTraversal;
26 import org.w3c.dom.traversal.NodeFilter;
27 import org.w3c.dom.traversal.NodeIterator;
28 import sk.baka.ikslibs.ids.IDManager;
29 import sk.baka.ikslibs.splitted.SplittedDocHolder;
30 import sk.uniba.euromath.Const;
31 import sk.uniba.euromath.document.schema.DocumentSchema;
32 import sk.uniba.euromath.document.schema.plug.SchemaException;
33 import sk.uniba.euromath.document.DocumentView;
34 import sk.uniba.euromath.tools.URLDir;
35 /***
36 * Provides access to the document. Accessible from out of document package.
37 * Class is not intended to be instantiated by clients.
38 * @author Martin Vysny
39 */
40 public final class XMLAccess {
41 /***
42 * The document.
43 */
44 private final DomCore doc;
45 /***
46 * Table of views, that manages the transformations over the document. Value
47 * is ignored.
48 */
49 final Map<DocumentView, Object> views = new WeakHashMap<DocumentView, Object>();
50 /***
51 * The document modifier instance.
52 */
53 private final DocumentModifier docModifier;
54 /***
55 * DocumentModifyHelper instace for clients.
56 */
57 private final DocumentModifyHelper docModifyHelper;
58 /***
59 * The document listeners manager instance.
60 */
61 private final DocumentListeners docListeners;
62 /***
63 * The undo manager.
64 */
65 private final UndoManager undoManager;
66 /***
67 * The export manager.
68 */
69 private final ExportManager exportManager;
70 /***
71 * Constructs a new instance of XMLAccess. For each opened document there is
72 * exactly one instance. Produced via the {@link DocumentFactory} factory.
73 * @param doc The document.
74 */
75 XMLAccess(DomCore doc) {
76 super();
77 this.doc = doc;
78 doc.xmlAccess = this;
79 exportManager = new ExportManager(this);
80 docListeners = new DocumentListeners(this);
81 docListeners.addModifierListener(doc.getNsManager().modifierListener);
82 undoManager = new UndoManager();
83 docModifier = new DocumentModifier(doc, views.keySet(), docListeners);
84 docModifyHelper = new DocumentModifyHelper(this);
85 undoManager.observe(doc.getDocument());
86 }
87 /***
88 * Opens new view on the document. The view must be initialized.
89 * @param view the view to register.
90 */
91 public void openView(final DocumentView view) {
92 if (!view.isInitialized())
93 throw new IllegalArgumentException("The view is not initialized");
94 if (view.isClosed())
95 throw new IllegalArgumentException("The view is closed");
96 views.put(view, null);
97 }
98 /***
99 * Unregisters the view. The view is no more used by the transformation
100 * engine and is subject to garbage collection.
101 * @param view the document view to close. Fails if the view was not opened
102 * for this document.
103 */
104 public void closeView(final DocumentView view) {
105 if (views.remove(view) == null)
106 throw new IllegalArgumentException("Illegal view.");
107 view.close();
108 }
109 /***
110 * Returns instance of the undo manager for this document.
111 * @return the undo manager.
112 */
113 public UndoManager getUndoManager() {
114 return undoManager;
115 }
116 /***
117 * Returns all namespaces present in the document.
118 * @return set of namespaces. <code>null</code> namespace (nor empty
119 * namespace) does not occur in the returned set. Deprecated, use namespace
120 * manager methods.
121 */
122 @Deprecated
123 public Set<String> getAllNamespaces() {
124 final Set<String> result = new HashSet<String>(getNsManager()
125 .getAllNamespaces());
126 result.remove("");
127 return result;
128 }
129 /***
130 * <p>
131 * Access to the XML document. This document has this special feature: Every
132 * element has <code>emp:id</code> attribute, denoting ID of that element.
133 * </p>
134 * <p>
135 * WARNING: It's client responsibility to use returned reference for
136 * read-access only. Any change of the document leads to inconsistency and
137 * errorneous behaviour. For write-access use the
138 * <code>DocumentModifier</code> object obtained using the
139 * <code>getModifier()</code> method.
140 * </p>
141 * @return the DOM document.
142 */
143 public Document getDocument() {
144 return doc.getDocument();
145 }
146 /***
147 * Validates this document.
148 * @throws SchemaException if something goes wrong in the process of
149 * validation.
150 */
151 public void validate() throws SchemaException {
152 doc.getSchema().validate();
153 }
154 /***
155 * Returns document modifier, which is used to transparently modify the
156 * document.
157 * @return the document modifier instance.
158 */
159 public DocumentModifier getModifier() {
160 return docModifier;
161 }
162 /***
163 * Loads global schemas for all namespaces, present in the document, for
164 * which no local schema was loaded. It must be called before the Schema
165 * interface is used, to ensure that all schemata are properly loaded.
166 * @throws SchemaException if error happens during loading of schemas.
167 * @throws IOException if i/o error occurs
168 */
169 public void loadGlobalSchemas() throws SchemaException, IOException {
170 final Set<String> allNamespaces = new HashSet<String>(doc
171 .getNsManager().getAllNamespaces());
172 allNamespaces.remove("");
173 doc.getSchema().getRefs().loadSchemata(allNamespaces);
174 }
175 /***
176 * Document's content modifier helper. For chosen operation returns all
177 * possibilities of document modification, that will result in valid
178 * document.
179 * @return the document schema instance.
180 */
181 public DocumentSchema getSchema() {
182 return doc.getSchema();
183 }
184 /***
185 * Returns ID manager, that maps IDs to nodes and vice versa.
186 * @return Id mapper.
187 */
188 public IDManager getIdManager() {
189 return doc.getIDManager();
190 }
191 /***
192 * Returns namespace manager for this document.
193 * @return namespace manager for this document.
194 */
195 public NamespaceManager getNsManager() {
196 return doc.getNsManager();
197 }
198 /***
199 * Returns entity manager for this document.
200 * @return entity manager for this document.
201 */
202 public sk.baka.ikslibs.ref.EntityManager getEntityManager() {
203 return doc.getEntityManager();
204 }
205 /***
206 * Returns document content retriever for this document.
207 * @return document content retriever for this document.
208 */
209 public DocumentContent getContent() {
210 return doc.getContent();
211 }
212 /***
213 * Serializes in-memory document to specified output stream.
214 * @param out stream, where to store saved xml.
215 * @param encoding the encoding. If <code>null</code>, then UTF-8 is
216 * used.
217 * @param prettyFormatting if output xml will be pretty-formatted - readable
218 * by user. Warning: this adds some whitespaces to xml, thus modifying
219 * result xml. User must be sure that these whitespaces are discardable.
220 */
221 public void saveDocument(OutputStream out, String encoding,
222 boolean prettyFormatting) {
223 final DOMImplementationLS impl = (DOMImplementationLS) doc
224 .getDocument().getImplementation();
225 final LSSerializer serializer = impl.createLSSerializer();
226 final LSOutput output = impl.createLSOutput();
227 output.setEncoding(encoding == null ? "UTF-8" : encoding);
228 output.setByteStream(out);
229
230 final Document serializeDoc = (Document) doc.getDocument().cloneNode(
231 true);
232
233 final NodeIterator i = ((DocumentTraversal) serializeDoc)
234 .createNodeIterator(serializeDoc.getDocumentElement(),
235 NodeFilter.SHOW_ELEMENT, null, false);
236 Element actNode = (Element) i.nextNode();
237 while (actNode != null) {
238
239 actNode.removeAttributeNS(Const.EM_URI,
240 Const.EM_ATTRIBUTE_ID_LOCALNAME);
241
242 actNode = (Element) i.nextNode();
243 }
244 i.detach();
245
246 doc.getNsManager().createXmlnsAttributes(
247 serializeDoc.getDocumentElement());
248
249 serializer.write(serializeDoc, output);
250 }
251 /***
252 * Returns encoding, in which the document is serialized. May return
253 * <code>null</code> if the encoding was not specified.
254 * @return the encoding.
255 */
256 public String getEncoding() {
257 return doc.getDocument().getXmlEncoding();
258 }
259 /***
260 * Serializes transformed document "as-is", no emp:id removal is performed.
261 * Used only for debug. Serializes only root fragment.
262 * @param out the outputstream.
263 */
264 public void serialize(OutputStream out) {
265 final DOMImplementationLS impl = (DOMImplementationLS) doc
266 .getDocument().getImplementation();
267 final LSSerializer serializer = impl.createLSSerializer();
268 final LSOutput output = impl.createLSOutput();
269 output.setEncoding("UTF-8");
270 output.setByteStream(out);
271
272 serializer.write(doc.getSplittedDoc().getRootFragment(), output);
273 }
274 /***
275 * DO NOT USE!!! For testing purposes only.
276 * @return domproxy
277 * @deprecated
278 */
279 @Deprecated
280 public DomCore getDomProxy() {
281 return doc;
282 }
283 /***
284 * Returns document listeners manager for this document.
285 * @return document listeners manager for this document.
286 */
287 public DocumentListeners getListeners() {
288 return docListeners;
289 }
290 /***
291 * Returns the export manager for this document.
292 * @return the export manager for this document.
293 */
294 public ExportManager getExportManager() {
295 return exportManager;
296 }
297 /***
298 * Returns full URI address of the document.
299 * @return document location.
300 */
301 public URL getDocumentURL() {
302 return doc.fileURL;
303 }
304 /***
305 * Returns the name of the document file, including the extension, without
306 * the path specifier.
307 * @return the file name without the path.
308 */
309 public String getFileName() {
310 return doc.fileName;
311 }
312 /***
313 * Returns URL pointing to the directory where the document is located.
314 * @return location of the XML file.
315 */
316 public URLDir getRoot() {
317 return doc.root;
318 }
319 /***
320 * Returns object accessing the 'splitted' image of the document.
321 * @return A <code>DomToSplitted</code> for this document.
322 */
323 public SplittedDocHolder getSplittedDoc() {
324 return doc.getSplittedDoc();
325 }
326 /***
327 * Returns clients Helper for modifying.
328 * @return DocumentModifyHelper instance
329 */
330 public DocumentModifyHelper getDocumentModifyHelper() {
331 return docModifyHelper;
332 }
333 }