1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22 package org.millscript.millscript.render;
23
24 import org.millscript.commons.util.IList;
25 import org.millscript.commons.util.MapIterator;
26 import org.millscript.commons.vfs.VFile;
27 import org.millscript.millscript.alert.Alerts;
28 import org.millscript.millscript.conf.Configuration;
29 import org.millscript.millscript.datatypes.CDATA;
30 import org.millscript.millscript.datatypes.XmlComment;
31 import org.millscript.millscript.tools.CharacterEntity;
32
33 import java.io.BufferedWriter;
34 import java.io.IOException;
35 import java.io.OutputStreamWriter;
36 import java.io.Writer;
37 import java.nio.charset.Charset;
38 import java.nio.charset.CharsetEncoder;
39 import java.nio.charset.CodingErrorAction;
40 import java.util.Iterator;
41 import java.util.List;
42
43 /**
44 * This abstract renderer provides the core functionality required by most
45 * renderer implementations.
46 */
47 public abstract class AbstractRenderer implements Renderer {
48
49 /**
50 * The set of character entities that are available to this renderer.
51 */
52 protected final CharacterEntity availableEntities;
53
54 /**
55 * The configuration for this renderer.
56 */
57 protected final Configuration config;
58
59 /**
60 * The character set this renderer is using for output.
61 */
62 protected final Charset outputCharset;
63
64 /**
65 * The character set encoder this renderer is using for output.
66 */
67 protected final CharsetEncoder outputEncoder;
68
69 /**
70 * The writer we are rendering into.
71 */
72 protected final Writer outputWriter;
73
74 /**
75 * The virtual file we are rendering to.
76 */
77 protected final VFile outputVFile;
78
79 /**
80 * Constructs a new abstract renderer, to render to the specified file,
81 * with the given set of character entities and output character set.
82 *
83 * @param ce the set of character entities to render with
84 * @param conf the configuration for this renderer
85 * @param cs the output character set
86 * @param file the virtual output file
87 */
88 public AbstractRenderer( final CharacterEntity ce, final Configuration conf, final Charset cs, final VFile file ) {
89 this.availableEntities = ce;
90 this.config = conf;
91 this.outputCharset = cs;
92 this.outputEncoder = cs.newEncoder();
93
94
95 this.outputEncoder.onMalformedInput( CodingErrorAction.REPORT );
96 this.outputEncoder.onUnmappableCharacter( CodingErrorAction.REPORT );
97 this.outputVFile = file;
98
99 this.outputWriter = new BufferedWriter(
100 new OutputStreamWriter(
101 file.getOutputStream(),
102 this.outputEncoder
103 ),
104 16384
105 );
106 }
107
108 /**
109 * Constructs a new abstract renderer, to render to the specified file,
110 * with the no character entities and output character set.
111 *
112 * @param conf the configuration for this renderer
113 * @param file the virtual output file
114 */
115 public AbstractRenderer( final Configuration conf, final VFile file ) {
116 this( null, conf, conf.getOutputCharset(), file );
117 }
118
119 /**
120 * Constructs a new abstract renderer, to render to the specified file,
121 * with the no character entities and output character set.
122 *
123 * @param cs the output character set
124 * @param file the virtual output file
125 */
126 public AbstractRenderer( final Configuration conf, final Charset cs, final VFile file ) {
127 this( null, conf, cs, file );
128 }
129
130 /**
131 * @see org.millscript.millscript.render.Renderer#append(java.lang.CharSequence)
132 */
133 public void append( final CharSequence cs ) throws IOException {
134 int len = cs.length();
135 for ( int i = 0; i < len; i++ ) {
136 this.append( cs.charAt( i ) );
137 }
138 }
139
140 /**
141 * @see org.millscript.millscript.render.Renderer#appendNoEscape(java.lang.CharSequence)
142 */
143 public void appendNoEscape( final CharSequence cs ) throws IOException {
144 int len = cs.length();
145 for ( int i = 0; i < len; i++ ) {
146 this.appendNoEscape( cs.charAt( i ) );
147 }
148 }
149
150 /**
151 * Checks if the specified character can be encoded by this renderer.
152 *
153 * @param ch the character to check
154 * @return <code>true</code> if the character can be encoded by this
155 * renderer
156 */
157 public final boolean canEncode( final char ch ) {
158 return this.outputEncoder.canEncode( ch );
159 }
160
161 /**
162 * @see org.millscript.millscript.render.Renderer#render(java.lang.Object)
163 */
164 public void render( final Object o ) throws IOException {
165 if ( o == null ) {
166 return;
167 } else if ( o instanceof Renderable ) {
168 ((Renderable) o).render( this );
169 } else if ( o instanceof IList ) {
170 MapIterator it = ((IList) o).iterator( true );
171 while ( it.hasNext() ) {
172 this.render( it.nextValue() );
173 }
174 } else if ( o instanceof List ) {
175 Iterator it = ((List)o).iterator();
176 while ( it.hasNext() ) {
177 this.render( it.next() );
178 }
179 } else {
180
181
182
183
184 this.renderObject( o );
185 }
186 }
187
188
189 /**
190 * @see org.millscript.millscript.render.Renderer#renderAsDocument(java.lang.Object)
191 */
192 public final void renderAsDocument( final Object o ) {
193 try {
194 this.renderDocumentHeader();
195 this.render( o );
196 this.renderDocumentFooter();
197 this.outputWriter.flush();
198 this.outputWriter.close();
199 } catch ( IOException ex ) {
200 throw(
201 Alerts.eval(
202 "Could not write to file",
203 null
204 ).
205 culprit( "file", this.outputVFile ).
206 culprit( "message", ex.getMessage() ).
207 mishap()
208 );
209 }
210 };
211
212 /**
213 * @see org.millscript.millscript.render.Renderer#renderAsFragment(org.millscript.commons.util.IList)
214 */
215 public final void renderAsFragment( final IList< ? > l ) {
216 try {
217 this.render( l );
218 this.outputWriter.flush();
219 this.outputWriter.close();
220 } catch ( IOException ex ) {
221 throw(
222 Alerts.eval(
223 "Could not write to file",
224 null
225 ).
226 culprit( "file", this.outputVFile ).
227 culprit( "message", ex.getMessage() ).
228 mishap()
229 );
230 }
231 }
232
233 /**
234 * @see org.millscript.millscript.render.Renderer#renderCDATA(org.millscript.millscript.datatypes.CDATA)
235 */
236 public void renderCDATA( final CDATA c ) throws IOException {
237
238
239 final Object[] kids = c.getStore();
240 final int nkids = kids.length;
241 for ( int i = 0; i < nkids; i++ ) {
242 this.render( kids[ i ] );
243 }
244 }
245
246 /**
247 * @see org.millscript.millscript.render.Renderer#renderXMLComment(org.millscript.millscript.datatypes.XmlComment)
248 */
249 public void renderXMLComment( final XmlComment c ) throws IOException {
250 this.appendNoEscape( c.toString() );
251 }
252
253 }