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.Transformer;
52 import javax.xml.transform.TransformerConfigurationException;
53 import javax.xml.transform.TransformerException;
54 import javax.xml.transform.TransformerFactory;
55 import javax.xml.transform.TransformerFactoryConfigurationError;
56 import javax.xml.transform.stream.StreamResult;
57
58
59
60
61
62 public final class XmlTransformer
63 {
64 public static final String PROPERTY_TRANSFORMER_POOL_SIZE = "service.xmlTransformer.transformerPoolSize";
65 public static final int TRANSFORMER_POOL_SIZE = AppPropertiesService.getPropertyInt( PROPERTY_TRANSFORMER_POOL_SIZE,
66 2 );
67 public static final int MAX_TRANSFORMER_SIZE = 1000;
68 private static final List<ConcurrentMap<String, Transformer>> transformerPoolList = new ArrayList<ConcurrentMap<String, Transformer>>( TRANSFORMER_POOL_SIZE );
69
70 static
71 {
72 for ( int i = 0; i < TRANSFORMER_POOL_SIZE; i++ )
73 {
74 transformerPoolList.add( new ConcurrentHashMap<String, Transformer>( MAX_TRANSFORMER_SIZE ) );
75 }
76 }
77
78
79
80
81
82
83
84
85 private Transformer getTransformer( Source stylesheet, String strStyleSheetId )
86 throws Exception
87 {
88 Transformer result = null;
89
90 if ( TRANSFORMER_POOL_SIZE > 0 )
91 {
92 int nTransformerListIndex = 0;
93
94 do
95 {
96 result = transformerPoolList.get( nTransformerListIndex ).remove( strStyleSheetId );
97 nTransformerListIndex++;
98 }
99 while ( ( result == null ) && ( nTransformerListIndex < TRANSFORMER_POOL_SIZE ) );
100 }
101
102 if ( result == null )
103 {
104
105 try
106 {
107 result = TransformerFactory.newInstance( ).newTransformer( stylesheet );
108 AppLogService.debug( " -- XML Transformer instantiation : strStyleSheetId=" + strStyleSheetId );
109 }
110 catch ( TransformerConfigurationException e )
111 {
112 String strMessage = e.getMessage( );
113
114 if ( e.getLocationAsString( ) != null )
115 {
116 strMessage += ( "- location : " + e.getLocationAsString( ) );
117 }
118
119 throw new Exception( "Error transforming document XSLT : " + strMessage, e.getCause( ) );
120 }
121 catch ( TransformerFactoryConfigurationError e )
122 {
123 throw new Exception( "Error transforming document XSLT : " + e.getMessage( ), e );
124 }
125 }
126 else
127 {
128
129 result.clearParameters( );
130 result.setOutputProperties( null );
131 }
132
133 return result;
134 }
135
136
137
138
139 public static void cleanTransformerList( )
140 {
141 for ( ConcurrentMap<String, Transformer> transformerList : transformerPoolList )
142 {
143 transformerList.clear( );
144 }
145 }
146
147
148
149
150
151 public static int getTransformersCount( )
152 {
153 int nCount = 0;
154
155 for ( ConcurrentMap<String, Transformer> transformerList : transformerPoolList )
156 {
157 nCount += transformerList.size( );
158 }
159
160 return nCount;
161 }
162
163
164
165
166
167
168 private void releaseTransformer( Transformer transformer, String strStyleSheetId )
169 {
170 if ( TRANSFORMER_POOL_SIZE > 0 )
171 {
172 Transformer result = null;
173 ConcurrentMap<String, Transformer> transformerList = null;
174 int nTransformerListIndex = 0;
175
176 do
177 {
178 transformerList = transformerPoolList.get( nTransformerListIndex );
179 nTransformerListIndex++;
180
181
182 if ( transformerList.size( ) < MAX_TRANSFORMER_SIZE )
183 {
184 result = transformerList.putIfAbsent( strStyleSheetId, transformer );
185 }
186 else
187 {
188
189 transformerList.clear( );
190
191 AppLogService.info( "XmlTransformer : cache is full, you may need to increase cache size." );
192 }
193 }
194 while ( ( result != null ) && ( nTransformerListIndex < TRANSFORMER_POOL_SIZE ) );
195 }
196 }
197
198
199
200
201
202
203
204
205
206
207
208 public String transform( Source source, Source stylesheet, String strStyleSheetId, Map<String, String> params,
209 Properties outputProperties ) throws Exception
210 {
211 Transformer transformer = this.getTransformer( stylesheet, strStyleSheetId );
212
213 if ( outputProperties != null )
214 {
215 transformer.setOutputProperties( outputProperties );
216 }
217
218 if ( params != null )
219 {
220 transformer.clearParameters( );
221
222 for ( Entry<String, String> entry : params.entrySet( ) )
223 {
224 transformer.setParameter( entry.getKey( ), entry.getValue( ) );
225 }
226 }
227
228 StringWriter sw = new StringWriter( );
229 Result result = new StreamResult( sw );
230
231 try
232 {
233 transformer.transform( source, result );
234 }
235 catch ( TransformerException e )
236 {
237 String strMessage = "strStyleSheetId = " + strStyleSheetId + " " + e.getMessage( );
238
239 if ( e.getLocationAsString( ) != null )
240 {
241 strMessage += ( " - location : " + e.getLocationAsString( ) );
242 }
243
244 throw new Exception( "Error transforming document XSLT : " + strMessage, e.getCause( ) );
245 }
246 finally
247 {
248 this.releaseTransformer( transformer, strStyleSheetId );
249 }
250
251 return sw.toString( );
252 }
253 }