KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > sun > enterprise > util > RelativePathResolver


1 /*
2  * The contents of this file are subject to the terms
3  * of the Common Development and Distribution License
4  * (the License). You may not use this file except in
5  * compliance with the License.
6  *
7  * You can obtain a copy of the license at
8  * https://glassfish.dev.java.net/public/CDDLv1.0.html or
9  * glassfish/bootstrap/legal/CDDLv1.0.txt.
10  * See the License for the specific language governing
11  * permissions and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL
14  * Header Notice in each file and include the License file
15  * at glassfish/bootstrap/legal/CDDLv1.0.txt.
16  * If applicable, add the following below the CDDL Header,
17  * with the fields enclosed by brackets [] replaced by
18  * you own identifying information:
19  * "Portions Copyrighted [year] [name of copyright owner]"
20  *
21  * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
22  */

23 package com.sun.enterprise.util;
24
25 import com.sun.enterprise.util.i18n.StringManager;
26 import java.io.File JavaDoc;
27
28 import com.sun.enterprise.util.i18n.StringManagerBase;
29 import com.sun.logging.LogDomains;
30
31 import com.sun.enterprise.security.store.PasswordAdapter;
32 import com.sun.enterprise.security.store.IdentityManager;
33 import java.io.IOException JavaDoc;
34 import java.security.KeyStoreException JavaDoc;
35 import java.security.NoSuchAlgorithmException JavaDoc;
36 import java.security.UnrecoverableKeyException JavaDoc;
37 import java.security.cert.CertificateException JavaDoc;
38
39 import java.util.logging.Logger JavaDoc;
40 import java.util.logging.Level JavaDoc;
41 import java.util.ArrayList JavaDoc;
42
43 /**
44  * The purpose of this class is to expand paths that contain embedded
45  * system properties of the form ${property-name}. The result must be
46  * an absolute path, or messages are logged. Here are some examples:
47  *
48  * ${com.sun.aas.installRoot}/config/domain.xml
49  * /foo/${config}/domain.xml
50  * /foo/${config}/${domain-name}
51  *
52  * This class is used to map paths containing system properties in
53  * domain.xml and used so that absolute paths (which are installation
54  * directory specific) are not present, making domain.xml portable
55  * in an SE/EE environment across many machines (with different
56  * installation directories).
57  */

58 public class RelativePathResolver {
59     
60     private static Logger JavaDoc _logger = null;
61
62     private static RelativePathResolver _instance = null;
63     private PasswordAdapter pwdAdapter = null;
64     
65     private static final String JavaDoc ALIAS_TOKEN = "ALIAS";
66     private static final String JavaDoc ALIAS_DELIMITER = "=";
67     
68     protected synchronized static Logger JavaDoc getLogger() {
69         if (_logger == null) {
70             _logger = LogDomains.getLogger(LogDomains.UTIL_LOGGER);
71         }
72         return _logger;
73     }
74    
75     private synchronized static RelativePathResolver getInstance()
76     {
77         if (_instance == null) {
78             _instance = new RelativePathResolver();
79         }
80         return _instance;
81     }
82     
83     public static String JavaDoc unresolvePath(String JavaDoc path, String JavaDoc[] propNames)
84     {
85         return getInstance().unresolve(path, propNames);
86     }
87     
88     public static String JavaDoc resolvePath(String JavaDoc path)
89     {
90         return getInstance().resolve(path);
91     }
92     
93     public RelativePathResolver()
94     {
95     }
96
97     /**
98      * unresolvePath will replace the first occurrence of the value of the given
99      * system properties with ${propName} in the given path
100      **/

101     public String JavaDoc unresolve(String JavaDoc path, String JavaDoc[] propNames) {
102         if (path != null) {
103             int startIdx;
104             String JavaDoc propVal;
105             
106             //All paths returned will contain / as the separator. The
107
//assumption is that the File class can convert this to an OS
108
//dependent path separator (e.g. \\ on windows).
109
path = path.replace(File.separatorChar, '/');
110             for (int i = 0; i < propNames.length; i++) {
111                 propVal = getPropertyValue(propNames[i], true);
112                 if (propVal != null) {
113                     //All paths returned will contain / as the separator. This will allow
114
//all comparison to be done using / as the separator
115
propVal = propVal.replace(File.separatorChar, '/');
116                     startIdx = path.indexOf(propVal);
117                     if (startIdx >= 0) {
118                         path = path.substring(0, startIdx) +
119                             "${" + propNames[i] + "}" +
120                             path.substring(startIdx + propVal.length());
121                     }
122                 } else {
123                     getLogger().log(Level.SEVERE,
124                         "enterprise_util.path_unresolver_missing_property",
125                         new Object JavaDoc[] {propNames[i], path});
126                 }
127             }
128         }
129         return path;
130     }
131
132     /**
133      * You would like to think that we could just log and continue (without throwing
134      a RuntimeException; however, unfortunately anything logged by the logger in the
135      * launcher (PELaucnhFilter) does not appear in server.log, so for now, this
136      * will be considered a fatal error.
137      */

138     protected void fatalError(String JavaDoc message, String JavaDoc path) {
139         getLogger().log(Level.SEVERE, message, new Object JavaDoc[] {path});
140         StringManagerBase sm = StringManagerBase.getStringManager(getLogger().getResourceBundleName());
141         throw new RuntimeException JavaDoc(sm.getString(message, path));
142     }
143        
144     private void appendChar (char c, StringBuffer JavaDoc propName, StringBuffer JavaDoc result)
145     {
146         if (propName == null) {
147             result.append(c);
148         } else {
149             propName.append(c);
150         }
151     }
152     
153    
154     /**
155      * check if a given property name matches AS alias pattern ${ALIAS=aliasname}.
156      * if so, return the aliasname, otherwise return null.
157      * @param propName The property name to resolve. ex. ${ALIAS=aliasname}.
158      * @return The aliasname or null.
159      */

160     static public String JavaDoc getAlias(String JavaDoc propName)
161     {
162        String JavaDoc aliasName=null;
163        String JavaDoc starter = "${" + ALIAS_TOKEN + "="; //no space is allowed in starter
164
String JavaDoc ender = "}";
165
166        propName = propName.trim();
167        if (propName.startsWith(starter) && propName.endsWith(ender) ) {
168            propName = propName.substring(starter.length() );
169            int lastIdx = propName.length() - 1;
170            if (lastIdx > 1) {
171               propName = propName.substring(0,lastIdx);
172               if (propName!=null)
173                  aliasName = propName.trim();
174            }
175        }
176        return aliasName;
177     }
178
179
180     /**
181      * Resolves the given property by returning its value as either
182      * 1) a system property of the form ${system-property-name}
183      * 2) a password alias property of the form ${ALIAS=aliasname}. Here the alias name
184      * is mapped to a password.
185      * @param propName The property name to resolve
186      * @return The resolved value of the property or null.
187      */

188     protected String JavaDoc getPropertyValue(String JavaDoc propName, boolean bIncludingEnvironmentVariables)
189     {
190         if(!bIncludingEnvironmentVariables)
191           return null;
192         
193         // Try finding the property as a system property
194
String JavaDoc result = System.getProperty(propName);
195         if (result == null) {
196             //If not found as a system property, the see if it is a password alias.
197
int idx1 = propName.indexOf(ALIAS_TOKEN);
198             if (idx1 >= 0) {
199                 int idx2 = propName.indexOf(ALIAS_DELIMITER, ALIAS_TOKEN.length());
200                 if (idx2 > 0) {
201                     String JavaDoc aliasName = propName.substring(idx2 + 1).trim();
202                     //System.err.println("aliasName " + aliasName);
203
try {
204                         if (pwdAdapter==null) {
205                             //The masterPassword in the IdentityManager is available only through
206
//a running DAS, server instance, or node agent.
207
String JavaDoc masterPassword = IdentityManager.getMasterPassword();
208                             pwdAdapter = new PasswordAdapter(masterPassword.toCharArray());
209                         }
210                         result = pwdAdapter.getPasswordForAlias(aliasName);
211                         //System.err.println("alias password " + result);
212
} catch (Exception JavaDoc ex) {
213                         getLogger().log(Level.WARNING, "enterprise_util.path_resolver_alias_exception",
214                             new Object JavaDoc[] {ex, aliasName, propName});
215                         getLogger().log(Level.FINE, "enterprise_util.path_resolver_alias_exception",
216                             ex);
217                     }
218                 }
219             }
220         }
221         return result;
222     }
223    
224     public String JavaDoc resolve(String JavaDoc path) {
225         return resolve(path, true);
226     }
227     /**
228      * Replace any system properties of the form ${property} in the given path. Note
229      * any mismatched delimiters (e.g. ${property/${property2} is considered a fatal
230      * error and for now causes a fatal RuntimeException to be thrown.
231      */

232     public String JavaDoc resolve(String JavaDoc path, boolean bIncludingEnvironmentVariables) {
233         if (path == null) {
234             return path;
235         }
236         
237         //Now parse through the given string one character at a time looking for the
238
//starting delimiter "${". Occurrences of "$" or "{" are valid characters;
239
//however once an occurrence of "${" is found, then "}" becomes a closing
240
//delimiter.
241
int size = path.length();
242         StringBuffer JavaDoc result = new StringBuffer JavaDoc(size);
243         StringBuffer JavaDoc propName = null;
244         String JavaDoc propVal;
245         //keep track of whether we have found at least one occurrence of "${". The
246
//significance is that "}" is parsed as a terminating character.
247
boolean foundOne = false;
248         char c;
249         for (int i = 0; i < size; i++) {
250             c = path.charAt(i);
251             switch(c) {
252                 case '$': {
253                     if (i < size - 1 && path.charAt(i + 1) == '{') {
254                         //found "${"
255
foundOne = true;
256                         i++;
257                         if (propName == null) { // start parsing a new property Name
258
propName = new StringBuffer JavaDoc();
259                             break;
260                         } else { // previous property not terminated missing }
261
fatalError(
262                                 "enterprise_util.path_resolver_missing_closing_delim",
263                                 path);
264                             return path; //can't happen since fatalError throws RuntimeException
265
}
266                     } else {
267                         appendChar(c, propName, result);
268                     }
269                     break;
270                 } case '}': {
271                     if (foundOne) { // we have found at least one occurrence of ${
272
if (propName != null) {
273                             propVal = getPropertyValue(propName.toString(), bIncludingEnvironmentVariables);
274                             if (propVal != null) {
275                                 //Note: when elaborating a system property, we always convert \\ to / to ensure that
276
//paths created on windows are compatible with unix filesystems.
277
result.append(propVal.replace(File.separatorChar, '/'));
278                             } else {
279                                 //NOTE: We cannot ensure that system properties will always
280
//be defined and so this is an expected case. Consider
281
//a property named ${http-listener-port}. This property
282
//may be defined at the server or config level and set only
283
//when that server instance starts up. The property may not
284
//be set in the DAS.
285
result.append("${" + propName + "}");
286                             }
287                             propName = null;
288                         } else { //no matching starting delimiter found ${
289
fatalError(
290                                 "enterprise_util.path_resolver_missing_starting_delim",
291                                 path);
292                             return path; //can't happen since fatalError throws RuntimeException
293
}
294                     } else {
295                         appendChar(c, propName, result);
296                     }
297                     break;
298                 } default : {
299                     appendChar(c, propName, result);
300                     break;
301                 }
302             }
303         }
304         
305         if (propName != null) { // missing final }
306
fatalError(
307                 "enterprise_util.path_resolver_missing_closing_delim",
308                 path);
309             return path; //can't happen
310
}
311         
312         return result.toString();
313     }
314     
315     /**
316      * checks if string does not consist of unresolvable values
317      */

318     public boolean isResolvable(String JavaDoc path, boolean bIncludingEnvironmentVariables) {
319         String JavaDoc resolved = resolve(path, bIncludingEnvironmentVariables);
320         return (resolved.indexOf("${")<0);
321     }
322     
323     public static void main(String JavaDoc[] args) {
324         if (args[0].equalsIgnoreCase("unresolve")) {
325             for (int i = 2; i < args.length; i++) {
326                 String JavaDoc result = unresolvePath(args[i], new String JavaDoc[] {args[1]});
327                 System.out.println(args[i] + " " + result + " " + resolvePath(result));
328             }
329         } else {
330             for (int i = 0; i < args.length; i++) {
331                 System.out.println(args[i] + " " + resolvePath(args[i]));
332             }
333         }
334     }
335     /** Returns the actual password from the domain-wide safe password store,
336      * if the given password is aliased. An aliased String is of the form
337      * ${ALIAS=aliasname} where the actual password is stored in given alias name.
338      * Following are the returned values:
339      * <ul>
340      * <li> Returns a null if given String is null. </li>
341      * <li> Retuns the given String if it is not in the alias form. </li>
342      * <li> Returns the real password from store if the given String is
343      * of the alias form and the alias has been created by the
344      * administrator. If the alias is not defined in the store,
345      * an IllegalArgumentException is thrown with appropriate
346      * message. </li>
347      * </ul>
348      * @param at is the aliased token of the form "${ALIAS=string}"
349      * @return a String representing the actual password
350      * @throws IllegalArgumentException if the alias is not defined
351      * @throws KeyStoreException CertificateException IOException NoSuchAlgorithmException
352      * UnrecoverableKeyException if there is an error is opening or
353      * processing the password store
354      */

355     public static String JavaDoc getRealPasswordFromAlias(final String JavaDoc at) throws
356             KeyStoreException JavaDoc, CertificateException JavaDoc, IOException JavaDoc, NoSuchAlgorithmException JavaDoc,
357             UnrecoverableKeyException JavaDoc {
358         try {
359             if (at == null || RelativePathResolver.getAlias(at) == null) {
360                 return ( at );
361             }
362         } catch (final Exception JavaDoc e) { //underlying code is unsafe!
363
return (at);
364         }
365         final String JavaDoc an = RelativePathResolver.getAlias(at);
366         final String JavaDoc sp = IdentityManager.getMasterPassword();
367         final PasswordAdapter pa = new PasswordAdapter(sp.toCharArray()); // use default password store
368
final boolean exists = pa.aliasExists(an);
369         if (!exists) {
370             final StringManager lsm = StringManager.getManager(RelativePathResolver.class);
371             final String JavaDoc msg = lsm.getString("no_such_alias", an, at);
372             throw new IllegalArgumentException JavaDoc(msg);
373         }
374         final String JavaDoc real = pa.getPasswordForAlias(an);
375         return ( real );
376     }
377 }
378
Popular Tags