1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34 package fr.paris.lutece.util.xml;
35
36 import fr.paris.lutece.portal.service.util.AppLogService;
37 import fr.paris.lutece.portal.service.util.AppPropertiesService;
38
39 import java.io.StringWriter;
40
41 import java.util.ArrayList;
42 import java.util.List;
43 import java.util.Map;
44 import java.util.Map.Entry;
45 import java.util.Properties;
46 import java.util.concurrent.ConcurrentHashMap;
47 import java.util.concurrent.ConcurrentMap;
48
49 import javax.xml.transform.Result;
50 import javax.xml.transform.Source;
51 import javax.xml.transform.Templates;
52 import javax.xml.transform.Transformer;
53 import javax.xml.transform.TransformerConfigurationException;
54 import javax.xml.transform.TransformerException;
55 import javax.xml.transform.TransformerFactory;
56 import javax.xml.transform.TransformerFactoryConfigurationError;
57 import javax.xml.transform.stream.StreamResult;
58
59
60
61
62 public final class XmlTransformer
63 {
64 private static final String ERROR_MESSAGE_XLST = "Error transforming document XSLT : ";
65 public static final String PROPERTY_TRANSFORMER_POOL_SIZE = "service.xmlTransformer.transformerPoolSize";
66 public static final int TRANSFORMER_POOL_SIZE = AppPropertiesService.getPropertyInt( PROPERTY_TRANSFORMER_POOL_SIZE, 2 );
67 public static final int MAX_TRANSFORMER_SIZE = 1000;
68 private static final List<ConcurrentMap<String, Templates>> transformersPoolList = new ArrayList<>( TRANSFORMER_POOL_SIZE );
69
70 static
71 {
72 for ( int i = 0; i < TRANSFORMER_POOL_SIZE; i++ )
73 {
74 transformersPoolList.add( new ConcurrentHashMap<String, Templates>( MAX_TRANSFORMER_SIZE ) );
75 }
76 }
77
78
79
80
81
82
83
84
85
86
87
88
89
90 private Templates getTemplates( Source stylesheet, String strStyleSheetId ) throws TransformerException
91 {
92 Templates result = null;
93
94 if ( TRANSFORMER_POOL_SIZE > 0 )
95 {
96 int nTransformerListIndex = 0;
97
98 do
99 {
100 result = transformersPoolList.get( nTransformerListIndex ).remove( strStyleSheetId );
101 nTransformerListIndex++;
102 }
103 while ( ( result == null ) && ( nTransformerListIndex < TRANSFORMER_POOL_SIZE ) );
104 }
105
106 if ( result == null )
107 {
108
109 try
110 {
111 result = TransformerFactory.newInstance( ).newTemplates( stylesheet );
112 AppLogService.debug( " -- XML Templates instantiation : strStyleSheetId= {}", strStyleSheetId );
113 }
114 catch( TransformerConfigurationException e )
115 {
116 String strMessage = e.getMessage( );
117
118 if ( e.getLocationAsString( ) != null )
119 {
120 strMessage += ( "- location : " + e.getLocationAsString( ) );
121 }
122
123 throw new TransformerException( ERROR_MESSAGE_XLST + strMessage, e.getCause( ) );
124 }
125 catch( TransformerFactoryConfigurationError e )
126 {
127 throw new TransformerException( ERROR_MESSAGE_XLST + e.getMessage( ), e );
128 }
129 }
130
131 return result;
132 }
133
134
135
136
137 public static void cleanTransformerList( )
138 {
139 for ( ConcurrentMap<String, Templates> transformerList : transformersPoolList )
140 {
141 transformerList.clear( );
142 }
143 }
144
145
146
147
148
149
150 public static int getTransformersCount( )
151 {
152 int nCount = 0;
153
154 for ( ConcurrentMap<String, Templates> transformerList : transformersPoolList )
155 {
156 nCount += transformerList.size( );
157 }
158
159 return nCount;
160 }
161
162
163
164
165
166
167
168
169
170 private void releaseTemplates( Templates templates, String strStyleSheetId )
171 {
172 if ( TRANSFORMER_POOL_SIZE > 0 )
173 {
174 Templates result = null;
175 ConcurrentMap<String, Templates> transformerList = null;
176 int nTransformerListIndex = 0;
177
178 do
179 {
180 transformerList = transformersPoolList.get( nTransformerListIndex );
181 nTransformerListIndex++;
182
183
184 if ( transformerList.size( ) < MAX_TRANSFORMER_SIZE )
185 {
186 result = transformerList.putIfAbsent( strStyleSheetId, templates );
187 }
188 else
189 {
190
191 transformerList.clear( );
192
193 AppLogService.info( "XmlTransformer : cache is full, you may need to increase cache size." );
194 }
195 }
196 while ( ( result != null ) && ( nTransformerListIndex < TRANSFORMER_POOL_SIZE ) );
197 }
198 }
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217 public String transform( Source source, Source stylesheet, String strStyleSheetId, Map<String, String> params, Properties outputProperties )
218 throws TransformerException
219 {
220 Templates templates = this.getTemplates( stylesheet, strStyleSheetId );
221 Transformer transformer = templates.newTransformer( );
222
223 if ( outputProperties != null )
224 {
225 transformer.setOutputProperties( outputProperties );
226 }
227
228 if ( params != null )
229 {
230 transformer.clearParameters( );
231
232 for ( Entry<String, String> entry : params.entrySet( ) )
233 {
234 transformer.setParameter( entry.getKey( ), entry.getValue( ) );
235 }
236 }
237
238 StringWriter sw = new StringWriter( );
239 Result result = new StreamResult( sw );
240
241 try
242 {
243 transformer.transform( source, result );
244 }
245 catch( TransformerException e )
246 {
247 String strMessage = "strStyleSheetId = " + strStyleSheetId + " " + e.getMessage( );
248
249 if ( e.getLocationAsString( ) != null )
250 {
251 strMessage += ( " - location : " + e.getLocationAsString( ) );
252 }
253
254 throw new TransformerException( ERROR_MESSAGE_XLST + strMessage, e.getCause( ) );
255 }
256 finally
257 {
258 this.releaseTemplates( templates, strStyleSheetId );
259 }
260
261 return sw.toString( );
262 }
263 }