001    /*--------------------------------------------------------------------------+
002    $Id: HTMLWriter.java 28096 2010-06-09 13:12:48Z hummelb $
003    |                                                                          |
004    | Copyright 2005-2010 Technische Universitaet Muenchen                     |
005    |                                                                          |
006    | Licensed under the Apache License, Version 2.0 (the "License");          |
007    | you may not use this file except in compliance with the License.         |
008    | You may obtain a copy of the License at                                  |
009    |                                                                          |
010    |    http://www.apache.org/licenses/LICENSE-2.0                            |
011    |                                                                          |
012    | Unless required by applicable law or agreed to in writing, software      |
013    | distributed under the License is distributed on an "AS IS" BASIS,        |
014    | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
015    | See the License for the specific language governing permissions and      |
016    | limitations under the License.                                           |
017    +--------------------------------------------------------------------------*/
018    package edu.tum.cs.commons.html;
019    
020    import java.io.File;
021    import java.io.IOException;
022    import java.io.OutputStream;
023    import java.io.OutputStreamWriter;
024    import java.io.PrintStream;
025    import java.io.PrintWriter;
026    import java.io.UnsupportedEncodingException;
027    
028    import edu.tum.cs.commons.filesystem.FileSystemUtils;
029    import edu.tum.cs.commons.string.StringUtils;
030    import edu.tum.cs.commons.xml.IXMLResolver;
031    import edu.tum.cs.commons.xml.XMLWriter;
032    
033    /**
034     * This class is used for writing HTML.
035     * 
036     * @author Benjamin Hummel
037     * @author $Author: hummelb $
038     * @version $Rev: 28096 $
039     * @levd.rating GREEN Hash: 8D23F1A3EAAA692885E5A25667EF254D
040     */
041    public class HTMLWriter extends XMLWriter<EHTMLElement, EHTMLAttribute> {
042    
043            /** The CSS manager class used. */
044            private final CSSManagerBase cssManager;
045    
046            /**
047             * Creates a new writer for HTML documents.
048             * 
049             * @param file
050             *            the file to write to.
051             */
052            public HTMLWriter(File file, CSSManagerBase cssManager) throws IOException {
053                    this(new PrintStream(file, FileSystemUtils.UTF8_ENCODING), cssManager);
054            }
055    
056            /**
057             * Creates a new writer for HTML documents.
058             * 
059             * @param stream
060             *            the stream to print to.
061             */
062            public HTMLWriter(OutputStream stream, CSSManagerBase cssManager) {
063                    super(new PrintWriter(wrapStream(stream)), new HTMLResolver());
064                    this.cssManager = cssManager;
065            }
066    
067            /**
068             * Helper method for {@link #HTMLWriter(OutputStream, CSSManagerBase)} to
069             * deal with the exception.
070             */
071            private static OutputStreamWriter wrapStream(OutputStream stream) {
072                    try {
073                            return new OutputStreamWriter(stream, FileSystemUtils.UTF8_ENCODING);
074                    } catch (UnsupportedEncodingException e) {
075                            throw new AssertionError("UTF-8 should be supported!");
076                    }
077            }
078    
079            /**
080             * Creates a new writer for HTML documents.
081             * 
082             * @param writer
083             *            the writer to print to.
084             */
085            public HTMLWriter(PrintWriter writer, CSSManagerBase cssManager) {
086                    super(writer, new HTMLResolver());
087                    this.cssManager = cssManager;
088            }
089    
090            /**
091             * This adds a default header for HTML files consisting of the XML header
092             * and a DOCTYPE of the xhtml frameset DTD.
093             * <p>
094             * XML version is set to "1.0", encoding provided by a parameter, and doc
095             * type definition to XHTML 1.0 Frameset.
096             */
097            public void addStdHeader(String encoding) {
098                    addHeader("1.0", encoding);
099                    addPublicDocTypeDefintion(EHTMLElement.HTML,
100                                    "-//W3C//DTD XHTML 1.0 Frameset//EN",
101                                    "http://www.w3.org/TR/xhtml1/DTD/xhtml1-frameset.dtd");
102            }
103    
104            /**
105             * This adds a default header for HTML files consisting of the XML header
106             * and a DOCTYPE of the xhtml frameset DTD.
107             * <p>
108             * XML version is set to "1.0", encoding to "UTF-8", and doc type definition
109             * to XHTML 1.0 Frameset.
110             */
111            public void addStdHeader() {
112                    addStdHeader(FileSystemUtils.UTF8_ENCODING);
113            }
114    
115            /**
116             * {@inheritDoc}
117             * 
118             * Made this public here.
119             */
120            @Override
121            public void addRawString(String html) {
122                    super.addRawString(html);
123            }
124    
125            /**
126             * Adds a line separator with closing and open tag (see
127             * {@link #addNewLine()}.
128             */
129            public void addRawNewLine() {
130                    addRawString(StringUtils.CR);
131            }
132    
133            /**
134             * Adds an attribute to the currently open element but checks in addition if
135             * the attribute may be added at all.
136             * 
137             * @throws HTMLWriterException
138             *             if the attribute is not allowed for the current element.
139             */
140            @Override
141            public void addAttribute(EHTMLAttribute attribute, Object value) {
142                    if (!getCurrentElement().allowsAttribute(attribute)) {
143                            throw new HTMLWriterException("Attribute " + attribute
144                                            + " not allowed for element " + getCurrentElement());
145                    }
146    
147                    if (attribute == EHTMLAttribute.STYLE
148                                    || attribute == EHTMLAttribute.CLASS) {
149                            if (!(value instanceof CSSDeclarationBlock)) {
150                                    throw new HTMLWriterException(
151                                                    "The argument for STYLE and CLASS attributes must be a "
152                                                                    + CSSDeclarationBlock.class.getSimpleName()
153                                                                    + "!");
154                            }
155                    }
156    
157                    if (attribute == EHTMLAttribute.STYLE) {
158                            super.addAttribute(attribute, ((CSSDeclarationBlock) value)
159                                            .toInlineStyle());
160                    } else if (attribute == EHTMLAttribute.CLASS) {
161                            super.addAttribute(attribute, cssManager
162                                            .getCSSClassName((CSSDeclarationBlock) value));
163                    } else {
164                            super.addAttribute(attribute, value);
165                    }
166            }
167    
168            /** The resolver used for the {@link HTMLWriter}. */
169            public static class HTMLResolver implements
170                            IXMLResolver<EHTMLElement, EHTMLAttribute> {
171    
172                    /** {@inheritDoc} */
173                    public String resolveAttributeName(EHTMLAttribute attribute) {
174                            return attribute.toString();
175                    }
176    
177                    /** {@inheritDoc} */
178                    public String resolveElementName(EHTMLElement element) {
179                            return element.toString();
180                    }
181    
182                    /** {@inheritDoc} */
183                    public Class<EHTMLAttribute> getAttributeClass() {
184                            return EHTMLAttribute.class;
185                    }
186            }
187    }