001    // Copyright 2006, 2007 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.tapestry.dom;
016    
017    import org.apache.tapestry.ioc.internal.util.Defense;
018    
019    import java.io.PrintWriter;
020    
021    /**
022     * The root node of a DOM.
023     */
024    public final class Document extends Node
025    {
026        private Element _rootElement;
027    
028        private DTD _dtd;
029    
030        private final MarkupModel _model;
031    
032        private final String _encoding;
033    
034        public Document(MarkupModel model)
035        {
036            this(model, null);
037        }
038    
039        public Document(MarkupModel model, String encoding)
040        {
041            super(null);
042    
043            _model = model;
044            _encoding = encoding;
045        }
046    
047        Document getDocument()
048        {
049            return this;
050        }
051    
052        /**
053         * Finds an element based on a path of element names.
054         *
055         * @param path slash separated series of element names
056         * @return the matching element, or null if not found
057         * @see Element#find(String)
058         */
059        public Element find(String path)
060        {
061            Defense.notBlank(path, "path");
062    
063            if (_rootElement == null) return null;
064    
065            int slashx = path.indexOf("/");
066    
067            String rootElementName = slashx < 0 ? path : path.substring(0, slashx);
068    
069            if (!_rootElement.getName().equals(rootElementName)) return null;
070    
071            return slashx < 0 ? _rootElement : _rootElement.find(path.substring(slashx + 1));
072        }
073    
074        /**
075         * Builds with an instance of {@link DefaultMarkupModel}.
076         */
077        public Document()
078        {
079            this(new DefaultMarkupModel());
080        }
081    
082        public MarkupModel getMarkupModel()
083        {
084            return _model;
085        }
086    
087        /**
088         * Creates the root element for this document, replacing any previous root element.
089         */
090        public Element newRootElement(String name)
091        {
092            _rootElement = new Element(this, null, name);
093    
094            return _rootElement;
095        }
096    
097        /**
098         * Creates a new root element within a namespace.
099         *
100         * @param namespace URI of namespace containing the element
101         * @param name      name of element with namespace
102         * @return the root element
103         */
104        public Element newRootElement(String namespace, String name)
105        {
106            _rootElement = new Element(this, namespace, name);
107    
108            return _rootElement;
109        }
110    
111        @Override
112        public void toMarkup(PrintWriter writer)
113        {
114            if (_rootElement == null) throw new IllegalStateException(DomMessages.noRootElement());
115    
116    
117            if (_model.isXML())
118            {
119                writer.print("<?xml version=\"1.0\"");
120    
121                if (_encoding != null) writer.printf(" encoding=\"%s\"", _encoding);
122    
123                writer.print("?>\n");
124            }
125    
126            // TODO: lead-in comments, directives.
127            if (_dtd != null)
128            {
129                _dtd.toMarkup(writer);
130            }
131    
132            _rootElement.toMarkup(writer);
133        }
134    
135        @Override
136        public String toString()
137        {
138            if (_rootElement == null) return "[empty Document]";
139    
140            return super.toString();
141        }
142    
143        public Element getRootElement()
144        {
145            return _rootElement;
146        }
147    
148        /**
149         * Tries to find an element in this document whose id is specified.
150         *
151         * @param id the value of the id attribute of the element being looked for
152         * @return the element if found. null if not found.
153         */
154        public Element getElementById(String id)
155        {
156            return _rootElement.getElementById(id);
157        }
158    
159        public void dtd(String name, String publicId, String systemId)
160        {
161            _dtd = new DTD(name, publicId, systemId);
162        }
163    }