1/*2 * Copyright 2000-2001,2004 The Apache Software Foundation.3 * 4 * Licensed under the Apache License, Version 2.0 (the "License");5 * you may not use this file except in compliance with the License.6 * You may obtain a copy of the License at7 * 8 * http://www.apache.org/licenses/LICENSE-2.09 * 10 * Unless required by applicable law or agreed to in writing, software11 * distributed under the License is distributed on an "AS IS" BASIS,12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.13 * See the License for the specific language governing permissions and14 * limitations under the License.15 */1617packageorg.apache.jetspeed.services.urlmanager;
1819// Java classes20import java.util.HashMap;
21import java.util.Hashtable;
22import java.util.Iterator;
23import java.util.List;
24import java.util.Map;
25import java.util.Vector;
26import java.io.BufferedWriter;
27import java.io.File;
28import java.io.FileWriter;
29import java.io.PrintWriter;
3031import javax.servlet.ServletConfig;
32import javax.servlet.ServletContext;
3334// Turbine classes35import org.apache.turbine.services.TurbineBaseService;
3637// Velocity classes38import org.apache.velocity.runtime.configuration.Configuration;
3940// Jetspeed classes41import org.apache.jetspeed.services.logging.JetspeedLogFactoryService;
42import org.apache.jetspeed.services.logging.JetspeedLogger;
43import org.apache.jetspeed.services.resources.JetspeedResources;
4445/***46 * <p>This implementation of the URLManagerService is backed by a simple47 * 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 URLManagerService54 * @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 */58publicclassJetspeedURLManagerServiceextends TurbineBaseService implements URLManagerService59 {
60/***61 * Static initialization of the logger for this class62 */63privatestaticfinalJetspeedLogger logger = JetspeedLogFactoryService.getLogger(JetspeedURLManagerService.class.getName());
6465/***66 Map used to store all URL Information.67 */68private Map urls = new HashMap();
6970/***71 Path to the properties file used for persisting the data72 */73private String path = null;
7475/***76 Hashtable to store proxy configuration in77 */78private Hashtable proxies = new Hashtable();
7980/***81 * Late init. Don't return control until early init says we're done.82 */83publicvoid init( )
84 {
85while( !getInit() ) {
86try {
87 Thread.sleep(500);
88 } catch (InterruptedException ie ) {
89 logger.info("URLManager service: Waiting for init()..." );
90 }
91 }
9293 }
94959697/***98 * Called during Turbine.init()99 *100 * @param config A ServletConfig.101 */102publicsynchronizedvoid init( ServletConfig config )
103 {
104//We have already been initialized...105if( getInit() ) return;
106107try108 {
109 logger.info ( "JetspeedURLManagerService early init()....starting!");
110111// Proxy Settings are stored as 'services.URLManager.proxy.<protocol>.port' and as112// 'services.URLManager.proxy.<protocol>.port' in JetspeedResource.properties.113// Get a list of settings and store them in the hashtable114 String prefix = "services." + URLManagerService.SERVICE_NAME + ".proxy.";
115 Iterator resourceKeys = JetspeedResources.getKeys( prefix );
116117 String key, hashKey;
118 Object hashValue = null;
119while( resourceKeys.hasNext() )
120 {
121 key = (String)resourceKeys.next();
122 hashKey = key.substring(prefix.length()).toLowerCase();
123if ( hashKey.endsWith(".host") )
124 {
125 hashValue = JetspeedResources.getString(key);
126 proxies.put( hashKey, hashValue );
127 }
128elseif ( hashKey.endsWith(".port") )
129 {
130 hashValue = new Integer(JetspeedResources.getInt(key));
131 proxies.put( hashKey, hashValue );
132 }
133 }
134135 path = JetspeedResources.getString( "services."+URLManagerService.SERVICE_NAME+".url" );
136137if ( path == null)
138 {
139 String tempdir = new String("WEB-INF/conf/datasources.properties");
140 String ps = System.getProperty("file.separator");
141142try143 {
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 }
151catch (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 }
158else159 {
160 logger.debug("URLMangler: will create file in user configured " + path);
161 path = config.getServletContext().getRealPath(path);
162// should test for writability here and fallback to servlet tmp directory on failure163 }
164165 load();
166 logger.info ( "JetspeedURLManagerService early init()....finished!");
167 }
168catch (Throwable t)
169 {
170 logger.error ( "Cannot initialize JetspeedURLManagerService!", t );
171 }
172 setInit(true);
173174 }
175176/***177 * Called during Turbine destroy(). Persist the Manager state178 * to disk179 */180publicvoid shutdown() {
181 save();
182 }
183184/***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 register189 */190publicvoid register( String url ) {
191if ( url != null ) {
192URLInfo info = getInfo( url );
193if ( info == null ) {
194 register( new URLInfo( url, URLManagerService.STATUS_OK ) );
195 }
196 }
197 }
198199/***200 * Registers a new URL record. If the url is already registered in 201 * the system, updates the status of this URL info record202 * 203 * @param url the url to register204 * @param status the status of this url205 */206publicvoid register( String url, int status ) {
207if ( url != null ) {
208URLInfo info = getInfo( url );
209if ( info == null ) {
210 register( new URLInfo( url, status ) );
211 } else {
212 info.setStatus( status );
213 }
214 }
215 }
216217/***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 record221 * 222 * @param url the url to register223 * @param status the status of this url224 * @param message a descriptive message of the status225 */226publicvoid register( String url, int status, String message ) {
227if ( url != null ) {
228URLInfo info = getInfo( url );
229if ( info == null ) {
230 register( new URLInfo( url, status, message ) );
231 } else {
232 info.setStatus( status );
233 info.setMessage( message );
234 }
235 }
236 }
237238/***239 * Register or replace an URL record. All records are keyed to240 * the imutable URL of URLInfo.241 * 242 * @param info the info record to store243 */244publicvoid register( URLInfo info ) {
245if ( info != null) {
246synchronized (urls) {
247if( getInfo( info.getURL() ) == null )
248 urls.put( info.getURL().intern(), info );
249 }
250 }
251 }
252253/***254 * Unregister an URL from the repository255 * 256 * @param url the url to remove257 */258publicvoid unregister( String url ) {
259if ( url != null ) {
260synchronized (urls) {
261 urls.remove( url.intern() );
262 }
263 }
264 }
265266/***267 * Get the information record stored in the database about268 * an URL.269 * 270 * @param url the url whose record is sought271 * @return the description record found in the repository or null.272 */273publicURLInfo getInfo( String url ) {
274URLInfo info = null;
275276if ( url != null ) {
277synchronized(urls) {
278 info = (URLInfo)urls.get( url.intern() );
279 }
280 }
281282return info;
283 }
284285/***286 * Test whether the URL is currently believed to be OK by this 287 * repository.288 * 289 * @param url the url to be tested290 * @return false is the url is known by this repository and has291 * a status indicating an error, true otherwise.292 */293publicboolean isOK( String url ) {
294URLInfo info = getInfo( url );
295296// we don't know this URL, play it safe and say it's good297if ( info == null ) returntrue;
298299return ( info.getStatus() == URLManagerService.STATUS_OK );
300 }
301302/***303 * List of the current known URLs in the repository304 *305 * @return a List of URL strings known to this repository306 */307public List list() {
308synchronized (urls) {
309returnnew Vector( urls.keySet() );
310 }
311 }
312313/***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 status319 * @return a List of URL strings known to this repository with this status320 */321public List list( int status ) {
322 Vector result = new Vector();
323324synchronized (urls) {
325 Iterator i = urls.entrySet().iterator();
326while( i.hasNext() ) {
327 Map.Entry entry = (Map.Entry)i.next();
328URLInfo info = (URLInfo)entry.getValue();
329if ( ( info.getStatus() & status ) != 0 ) {
330 result.addElement( entry.getKey() );
331 }
332 }
333 }
334335return result;
336 }
337338/***339 * Load the persisted state of the repository from disk340 */341privatesynchronizedvoid load() {
342343 Map store = new HashMap();
344 Configuration config = null;
345346 logger.info( "Restoring the URLs from disk: " + path );
347348try {
349 config = new Configuration( path );
350351int count = 1;
352 String url = null;
353354while ( ( url = ( config
355 .getString("entry."+count+".url") ) ) != null ) {
356//Intern the url to ensure we can use "==" to compare357//and synchronize on it358 url = url.intern();
359int status = config.getInteger("entry."+count+".status", URLManagerService.STATUS_OK );
360if( store.get( url ) == null )
361 store.put( url, new URLInfo( url, status ) );
362 count++;
363 }
364365 logger.info( "URLManager loaded " + count + " urls" );
366367 } catch ( Exception e ) {
368 logger.error( "Could not restore URLManager state", e );
369return;
370 } finally {
371// set the loaded store as the new store372this.urls = store;
373 }
374375 }
376377/***378 * Persist the state of the repository on disk in a properties file379 */380privatesynchronizedvoid save() {
381 PrintWriter pw = null ;
382383try {
384385 File propfile = new File(path); // FileWriter doesn't always do this386 propfile.getParentFile().mkdirs();
387 propfile.createNewFile();
388389 pw = new PrintWriter( new BufferedWriter( new FileWriter( propfile ) ) );
390synchronized (urls) {
391 Iterator i = urls.values().iterator();
392int entryNum = 1;
393while( i.hasNext() ) {
394URLInfo 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 }
409catch ( Throwable t )
410 {
411 logger.error( "Impossible to save URLManager state to "+path, t );
412 }
413finally414 {
415if( pw != null )
416 {
417 pw.close();
418 }
419 }
420 }
421422/***423 * Return the port of a proxy424 * @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 */427publicint getProxyPort( String protocol ) {
428 Integer proxyPort = (Integer)proxies.get( (protocol + ".port").toLowerCase() );
429430if (proxyPort != null)
431return proxyPort.intValue();
432else433return -1;
434 }
435436/***437 * Return a proxy's hostname438 * @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 protocol440 */441public String getProxyHost( String protocol ) {
442 String proxyHost = (String)proxies.get( (protocol + ".host").toLowerCase() );
443444return proxyHost;
445 }
446447/***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 output452 * @param element a value to be written453 */454protectedvoid writeEscaped( PrintWriter sink, String element ) {
455int upTo = element.indexOf(",");
456if( upTo == -1 ) {
457 sink.print( element );
458return;
459 }
460 sink.print( element.substring( 0, upTo ) );
461 sink.print( "//," );
462 writeEscaped( sink, element.substring( upTo+1, element.length() ) );
463return;
464 }
465 }