View Javadoc

1   /*
2    * Copyright 1999-2006 Faculty of Mathematics, Physics and Informatics, Comenius
3    * University, Bratislava. This file is protected by the Mozilla Public License
4    * version 1.1 (the "License"); you may not use this file except in compliance
5    * with the License. You may obtain a copy of the License at
6    * http://euromath2.sourceforge.net/license.html Unless required by applicable
7    * law or agreed to in writing, software distributed under the License is
8    * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
9    * KIND, either express or implied. See the License for the specific language
10   * governing permissions and limitations under the License.
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");//$NON-NLS-1$
94  		if (view.isClosed())
95  			throw new IllegalArgumentException("The view is closed");//$NON-NLS-1$
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."); //$NON-NLS-1$
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(""); //$NON-NLS-1$
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(""); //$NON-NLS-1$
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); //$NON-NLS-1$
228 		output.setByteStream(out);
229 		// duplicates document and prepares it for output.
230 		final Document serializeDoc = (Document) doc.getDocument().cloneNode(
231 				true);
232 		// removes all emp:ids
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 			// remove emp:id attribute
239 			actNode.removeAttributeNS(Const.EM_URI,
240 					Const.EM_ATTRIBUTE_ID_LOCALNAME);
241 			// get next element
242 			actNode = (Element) i.nextNode();
243 		}
244 		i.detach();
245 		// create namespace nodes
246 		doc.getNsManager().createXmlnsAttributes(
247 				serializeDoc.getDocumentElement());
248 		// serialize to stream
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"); //$NON-NLS-1$
270 		output.setByteStream(out);
271 		// serialize to stream
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 }