1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.apache.jetspeed.services.urlmanager;
18
19
20 import java.util.HashMap;
21 import java.util.Hashtable;
22 import java.util.Iterator;
23 import java.util.List;
24 import java.util.Map;
25 import java.util.Vector;
26 import java.io.BufferedWriter;
27 import java.io.File;
28 import java.io.FileWriter;
29 import java.io.PrintWriter;
30
31 import javax.servlet.ServletConfig;
32 import javax.servlet.ServletContext;
33
34
35 import org.apache.turbine.services.TurbineBaseService;
36
37
38 import org.apache.velocity.runtime.configuration.Configuration;
39
40
41 import org.apache.jetspeed.services.logging.JetspeedLogFactoryService;
42 import org.apache.jetspeed.services.logging.JetspeedLogger;
43 import org.apache.jetspeed.services.resources.JetspeedResources;
44
45 /***
46 * <p>This implementation of the URLManagerService is backed by a simple
47 * map persisted on disk in a properties file</p>
48 * Added: Support for proxies. <br>
49 * Example: (Set in <code>JetspeedResources.properties</code>)<br>
50 * <code>services.URLManager.proxy.http.host=myproxy.mydomain</code><br>
51 * <code>services.URLManager.proxy.http.port=81</code><br>
52 *
53 * @see URLManagerService
54 * @author <a href="mailto:raphael@apache.org">Raphaël Luta</a>
55 * @author <a href="mailto:sgala@hisitech.com">Santiago Gala</a>
56 * @version $Id: JetspeedURLManagerService.java,v 1.16 2004/02/23 03:30:47 jford Exp $
57 */
58 public class JetspeedURLManagerService extends TurbineBaseService implements URLManagerService
59 {
60 /***
61 * Static initialization of the logger for this class
62 */
63 private static final JetspeedLogger logger = JetspeedLogFactoryService.getLogger(JetspeedURLManagerService.class.getName());
64
65 /***
66 Map used to store all URL Information.
67 */
68 private Map urls = new HashMap();
69
70 /***
71 Path to the properties file used for persisting the data
72 */
73 private String path = null;
74
75 /***
76 Hashtable to store proxy configuration in
77 */
78 private Hashtable proxies = new Hashtable();
79
80 /***
81 * Late init. Don't return control until early init says we're done.
82 */
83 public void init( )
84 {
85 while( !getInit() ) {
86 try {
87 Thread.sleep(500);
88 } catch (InterruptedException ie ) {
89 logger.info("URLManager service: Waiting for init()..." );
90 }
91 }
92
93 }
94
95
96
97 /***
98 * Called during Turbine.init()
99 *
100 * @param config A ServletConfig.
101 */
102 public synchronized void init( ServletConfig config )
103 {
104
105 if( getInit() ) return;
106
107 try
108 {
109 logger.info ( "JetspeedURLManagerService early init()....starting!");
110
111
112
113
114 String prefix = "services." + URLManagerService.SERVICE_NAME + ".proxy.";
115 Iterator resourceKeys = JetspeedResources.getKeys( prefix );
116
117 String key, hashKey;
118 Object hashValue = null;
119 while( resourceKeys.hasNext() )
120 {
121 key = (String)resourceKeys.next();
122 hashKey = key.substring(prefix.length()).toLowerCase();
123 if ( hashKey.endsWith(".host") )
124 {
125 hashValue = JetspeedResources.getString(key);
126 proxies.put( hashKey, hashValue );
127 }
128 else if ( hashKey.endsWith(".port") )
129 {
130 hashValue = new Integer(JetspeedResources.getInt(key));
131 proxies.put( hashKey, hashValue );
132 }
133 }
134
135 path = JetspeedResources.getString( "services."+URLManagerService.SERVICE_NAME+".url" );
136
137 if ( path == null)
138 {
139 String tempdir = new String("WEB-INF/conf/datasources.properties");
140 String ps = System.getProperty("file.separator");
141
142 try
143 {
144 ServletContext sc = config.getServletContext();
145 tempdir = sc.getAttribute("javax.servlet.context.tempdir").toString()
146 + ps + "jetspeed"
147 + ps + "conf"
148 + ps + "datasources.properties";
149 logger.debug("URLMangler: will create file in servlet temp directory " + tempdir);
150 }
151 catch (Exception e)
152 {
153 logger.debug("URLMangler: problems creating file in servlet temp directory "
154 + " falling back to WEB-INF/conf : " + e);
155 }
156 path = tempdir;
157 }
158 else
159 {
160 logger.debug("URLMangler: will create file in user configured " + path);
161 path = config.getServletContext().getRealPath(path);
162
163 }
164
165 load();
166 logger.info ( "JetspeedURLManagerService early init()....finished!");
167 }
168 catch (Throwable t)
169 {
170 logger.error ( "Cannot initialize JetspeedURLManagerService!", t );
171 }
172 setInit(true);
173
174 }
175
176 /***
177 * Called during Turbine destroy(). Persist the Manager state
178 * to disk
179 */
180 public void shutdown() {
181 save();
182 }
183
184 /***
185 * Registers a new URL record. If the url is already registered in
186 * the system, doesn't modify the current record.
187 *
188 * @param url the url to register
189 */
190 public void register( String url ) {
191 if ( url != null ) {
192 URLInfo info = getInfo( url );
193 if ( info == null ) {
194 register( new URLInfo( url, URLManagerService.STATUS_OK ) );
195 }
196 }
197 }
198
199 /***
200 * Registers a new URL record. If the url is already registered in
201 * the system, updates the status of this URL info record
202 *
203 * @param url the url to register
204 * @param status the status of this url
205 */
206 public void register( String url, int status ) {
207 if ( url != null ) {
208 URLInfo info = getInfo( url );
209 if ( info == null ) {
210 register( new URLInfo( url, status ) );
211 } else {
212 info.setStatus( status );
213 }
214 }
215 }
216
217 /***
218 * Registers a new URL record. If the url is already registered in
219 * the system, updates both the status and the message of this URL
220 * info record
221 *
222 * @param url the url to register
223 * @param status the status of this url
224 * @param message a descriptive message of the status
225 */
226 public void register( String url, int status, String message ) {
227 if ( url != null ) {
228 URLInfo info = getInfo( url );
229 if ( info == null ) {
230 register( new URLInfo( url, status, message ) );
231 } else {
232 info.setStatus( status );
233 info.setMessage( message );
234 }
235 }
236 }
237
238 /***
239 * Register or replace an URL record. All records are keyed to
240 * the imutable URL of URLInfo.
241 *
242 * @param info the info record to store
243 */
244 public void register( URLInfo info ) {
245 if ( info != null) {
246 synchronized (urls) {
247 if( getInfo( info.getURL() ) == null )
248 urls.put( info.getURL().intern(), info );
249 }
250 }
251 }
252
253 /***
254 * Unregister an URL from the repository
255 *
256 * @param url the url to remove
257 */
258 public void unregister( String url ) {
259 if ( url != null ) {
260 synchronized (urls) {
261 urls.remove( url.intern() );
262 }
263 }
264 }
265
266 /***
267 * Get the information record stored in the database about
268 * an URL.
269 *
270 * @param url the url whose record is sought
271 * @return the description record found in the repository or null.
272 */
273 public URLInfo getInfo( String url ) {
274 URLInfo info = null;
275
276 if ( url != null ) {
277 synchronized(urls) {
278 info = (URLInfo)urls.get( url.intern() );
279 }
280 }
281
282 return info;
283 }
284
285 /***
286 * Test whether the URL is currently believed to be OK by this
287 * repository.
288 *
289 * @param url the url to be tested
290 * @return false is the url is known by this repository and has
291 * a status indicating an error, true otherwise.
292 */
293 public boolean isOK( String url ) {
294 URLInfo info = getInfo( url );
295
296
297 if ( info == null ) return true;
298
299 return ( info.getStatus() == URLManagerService.STATUS_OK );
300 }
301
302 /***
303 * List of the current known URLs in the repository
304 *
305 * @return a List of URL strings known to this repository
306 */
307 public List list() {
308 synchronized (urls) {
309 return new Vector( urls.keySet() );
310 }
311 }
312
313 /***
314 * List of the current known URLs in the repository which have
315 * the given status.
316 *
317 * @param status the status to be retrieved. May be
318 * {@link URLManagerService#STATUS_ANY} to indicate any status
319 * @return a List of URL strings known to this repository with this status
320 */
321 public List list( int status ) {
322 Vector result = new Vector();
323
324 synchronized (urls) {
325 Iterator i = urls.entrySet().iterator();
326 while( i.hasNext() ) {
327 Map.Entry entry = (Map.Entry)i.next();
328 URLInfo info = (URLInfo)entry.getValue();
329 if ( ( info.getStatus() & status ) != 0 ) {
330 result.addElement( entry.getKey() );
331 }
332 }
333 }
334
335 return result;
336 }
337
338 /***
339 * Load the persisted state of the repository from disk
340 */
341 private synchronized void load() {
342
343 Map store = new HashMap();
344 Configuration config = null;
345
346 logger.info( "Restoring the URLs from disk: " + path );
347
348 try {
349 config = new Configuration( path );
350
351 int count = 1;
352 String url = null;
353
354 while ( ( url = ( config
355 .getString("entry."+count+".url") ) ) != null ) {
356
357
358 url = url.intern();
359 int status = config.getInteger("entry."+count+".status", URLManagerService.STATUS_OK );
360 if( store.get( url ) == null )
361 store.put( url, new URLInfo( url, status ) );
362 count++;
363 }
364
365 logger.info( "URLManager loaded " + count + " urls" );
366
367 } catch ( Exception e ) {
368 logger.error( "Could not restore URLManager state", e );
369 return;
370 } finally {
371
372 this.urls = store;
373 }
374
375 }
376
377 /***
378 * Persist the state of the repository on disk in a properties file
379 */
380 private synchronized void save() {
381 PrintWriter pw = null ;
382
383 try {
384
385 File propfile = new File(path);
386 propfile.getParentFile().mkdirs();
387 propfile.createNewFile();
388
389 pw = new PrintWriter( new BufferedWriter( new FileWriter( propfile ) ) );
390 synchronized (urls) {
391 Iterator i = urls.values().iterator();
392 int entryNum = 1;
393 while( i.hasNext() ) {
394 URLInfo info = (URLInfo)i.next();
395 pw.print( "entry." );
396 pw.print( entryNum );
397 pw.print( ".url=" );
398 writeEscaped( pw, info.getURL() );
399 pw.println( "" );
400 pw.print( "entry." );
401 pw.print( entryNum );
402 pw.print( ".status=" );
403 pw.print( info.getStatus() );
404 pw.println( "" );
405 entryNum++;
406 }
407 }
408 }
409 catch ( Throwable t )
410 {
411 logger.error( "Impossible to save URLManager state to "+path, t );
412 }
413 finally
414 {
415 if( pw != null )
416 {
417 pw.close();
418 }
419 }
420 }
421
422 /***
423 * Return the port of a proxy
424 * @param protocol The protocol that the proxy supports, e.g. 'http'
425 * @return The port number (1-65535), or -1 if no port was specified (= use default)
426 */
427 public int getProxyPort( String protocol ) {
428 Integer proxyPort = (Integer)proxies.get( (protocol + ".port").toLowerCase() );
429
430 if (proxyPort != null)
431 return proxyPort.intValue();
432 else
433 return -1;
434 }
435
436 /***
437 * Return a proxy's hostname
438 * @param protocol The protocol that the proxy supports, e.g. 'http'
439 * @return The hostname of the proxy, or <code>null</code> if no proxy is specified for this protocol
440 */
441 public String getProxyHost( String protocol ) {
442 String proxyHost = (String)proxies.get( (protocol + ".host").toLowerCase() );
443
444 return proxyHost;
445 }
446
447 /***
448 * <p>Escape values when saving.
449 * Appends a String to a StringBuffer, escaping commas.</p>
450 * <p>We assume that commas are unescaped.</p>
451 * @param sink a StringBuffer to write output
452 * @param element a value to be written
453 */
454 protected void writeEscaped( PrintWriter sink, String element ) {
455 int upTo = element.indexOf(",");
456 if( upTo == -1 ) {
457 sink.print( element );
458 return;
459 }
460 sink.print( element.substring( 0, upTo ) );
461 sink.print( "//," );
462 writeEscaped( sink, element.substring( upTo+1, element.length() ) );
463 return;
464 }
465 }