View Javadoc

1   /*
2    * ModeShape (http://www.modeshape.org)
3    * See the COPYRIGHT.txt file distributed with this work for information
4    * regarding copyright ownership.  Some portions may be licensed
5    * to Red Hat, Inc. under one or more contributor license agreements.
6    * See the AUTHORS.txt file in the distribution for a full listing of 
7    * individual contributors.
8    *
9    * ModeShape is free software. Unless otherwise indicated, all code in ModeShape
10   * is licensed to you under the terms of the GNU Lesser General Public License as
11   * published by the Free Software Foundation; either version 2.1 of
12   * the License, or (at your option) any later version.
13   * 
14   * ModeShape is distributed in the hope that it will be useful,
15   * but WITHOUT ANY WARRANTY; without even the implied warranty of
16   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17   * Lesser General Public License for more details.
18   *
19   * You should have received a copy of the GNU Lesser General Public
20   * License along with this software; if not, write to the Free
21   * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
22   * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
23   */
24  package org.modeshape.jdbc.delegate;
25  
26  import java.sql.DriverPropertyInfo;
27  import java.util.ArrayList;
28  import java.util.List;
29  import java.util.Properties;
30  
31  import javax.jcr.Credentials;
32  import javax.jcr.SimpleCredentials;
33  
34  import org.modeshape.jcr.api.Repositories;
35  import org.modeshape.jdbc.JcrDriver;
36  import org.modeshape.jdbc.JdbcI18n;
37  import org.modeshape.jdbc.util.StringUtil;
38  import org.modeshape.jdbc.util.TextDecoder;
39  import org.modeshape.jdbc.util.UrlEncoder;
40  
41  /**
42   * The ConnectionInfo contains the information used to connect to the Jcr Repository.
43   * 
44   */
45  public abstract class ConnectionInfo {
46      public static final TextDecoder URL_DECODER = new UrlEncoder();
47  	
48      protected String url;
49      protected String repositoryPath;
50      protected Properties properties;
51      private char propertyDelimiter='?';
52  
53      protected ConnectionInfo(String url, Properties properties) {
54  		this.url = url;
55  		this.properties = properties;
56      }
57      
58      
59      protected void init() {
60  	    Properties props = getProperties() != null ? (Properties) getProperties().clone() : new Properties();
61  	    repositoryPath = getUrl().substring(this.getUrlPrefix().length());
62  		  
63  	    // Find any URL parameters ...
64  	    int questionMarkIndex = repositoryPath.indexOf('?');
65  	    if (questionMarkIndex != -1) {
66  			if (repositoryPath.length() > questionMarkIndex + 1) {
67  			    String paramStr = repositoryPath.substring(questionMarkIndex + 1);
68  			    for (String param : paramStr.split("&")) {
69  			    	String[] pair = param.split("=");
70  					if (pair.length > 1) {
71  					    String key = URL_DECODER
72  						    .decode(pair[0] != null ? pair[0].trim()
73  							    : null);
74  					    String value = URL_DECODER
75  						    .decode(pair[1] != null ? pair[1].trim()
76  							    : null);
77  					    if (!props.containsKey(key)) {
78  					    	props.put(key, value);
79  					    }
80  					}
81  			    }
82  			}
83  			repositoryPath = repositoryPath.substring(0, questionMarkIndex).trim();
84  	    }
85  
86  	    Properties newprops = new Properties();
87  	    newprops.putAll(props);
88  	    this.setProperties(newprops);
89  	    String url = getUrl();
90  	    this.setUrl(url != null ? url.trim() : null);
91  
92      }
93      
94      /**
95       * Get the original URL of the connection.
96       * 
97       * @return the URL; never null
98       */
99      public String getUrl() {
100     	return url;
101     }
102     
103     /**
104      * Get the part of the {@link #getUrl()} that indicates the path to connect to the Repository.  
105      * This value should be prefixed by the {@link #getUrlPrefix()} in the {@link #getUrl()}.
106      * @return String
107      */
108     public String getRepositoryPath() {
109     	return this.repositoryPath;
110     }
111 
112     /**
113      * Get the immutable properties for the connection.
114      * 
115      * @return the properties; never null
116      */
117     public Properties getProperties() {
118     	return properties;
119     }
120 
121     /**
122      * Get the name of the repository. This is required only if the 
123      * {@link Repositories} instance is being used to obtain the Repository.
124      * 
125      * @return the name of the repository, or null if no repository name was
126      *         specified
127      */
128     public String getRepositoryName() {
129     	return properties.getProperty(JcrDriver.REPOSITORY_PROPERTY_NAME);
130     }
131     
132     /**
133      * Call to set the repository name.  This is called when no repository name is set 
134      * on the URL, but there is only one repository in the list.
135      * @param repositoryName
136      */
137     void setRepositoryName(String repositoryName) {
138     	this.properties.setProperty(JcrDriver.REPOSITORY_PROPERTY_NAME, repositoryName);
139     }
140 
141     /**
142      * Get the name of the workspace. This is not required, and if abscent
143      * implies obtaining the JCR Repository's default workspace.
144      * 
145      * @return the name of the workspace, or null if no workspace name was
146      *         specified
147      */
148     public String getWorkspaceName() {
149     	return properties.getProperty(JcrDriver.WORKSPACE_PROPERTY_NAME);
150     }
151     
152     /**
153      * Call to set the workspace name. This is not required, and if abscent
154      * implies obtaining the JCR Repository's default workspace.
155      * @param workSpaceName 
156 
157      */
158     public void setWorkspaceName(String workSpaceName) {
159     	properties.setProperty(JcrDriver.WORKSPACE_PROPERTY_NAME, workSpaceName);
160     }
161 
162     /**
163      * Get the JCR user name. This is not required, and if abscent implies that
164      * no credentials should be used when obtaining a JCR Session.
165      * 
166      * @return the JCR user name, or null if no user name was specified
167      */
168     public String getUsername() {
169     	return properties.getProperty(JcrDriver.USERNAME_PROPERTY_NAME);
170     }
171 
172     /**
173      * Get the JCR password. This is not required.
174      * 
175      * @return the JCR password, or null if no password was specified
176      */
177     public char[] getPassword() {
178 		String result = properties.getProperty(JcrDriver.PASSWORD_PROPERTY_NAME);
179 		return result != null ? result.toCharArray() : null;
180     }
181     
182     /**
183      * Return true of Teiid support is required for this connection.
184      * @return true if Teiid support is required.
185      */
186 	public boolean isTeiidSupport() {
187 		String result = properties.getProperty(JcrDriver.TEIID_SUPPORT_PROPERTY_NAME);
188 		if (result == null) return false;
189 		return result.equalsIgnoreCase(Boolean.TRUE.toString());
190     }
191 
192     void setUrl(String url) {
193     	this.url = url;
194     }
195 
196     void setProperties(Properties properties) {
197     	this.properties = properties;
198     }
199 
200 	/**
201 	 * Get the effective URL of this connection, which places all properties
202 	 * on the URL (with a '*' for each character in the password property)
203 	 * 
204 	 * @return the effective URL; never null
205 	 */
206 	public String getEffectiveUrl() {
207 	    StringBuilder url = new StringBuilder(this.getUrlPrefix());
208 	    url.append(this.getRepositoryPath());
209 	    char propertyDelim = getPropertyDelimiter();
210 	    for (String propertyName : getProperties().stringPropertyNames()) {
211 			String value = getProperties().getProperty(propertyName);
212 			if (value == null)
213 			    continue;
214 			if (JcrDriver.PASSWORD_PROPERTY_NAME.equals(propertyName)) {
215 			    value = StringUtil.createString('*', value.length());
216 			}
217 			url.append(propertyDelim).append(propertyName).append('=')
218 				.append(value);
219 			propertyDelim = '&';
220 	    }
221 	    return url.toString();
222 	}
223 	
224 	/**
225 	 * Return the starting property delimiter
226 	 * @return char property delimiter
227 	 */
228 	protected char getPropertyDelimiter() {
229 		return propertyDelimiter;
230 	}
231 	
232 	protected void setPropertyDelimiter(char delimiter) {
233 		this.propertyDelimiter = delimiter;
234 	}
235 	
236 	
237     
238     /**
239      * Obtain the array of {@link DriverPropertyInfo} objects that describe the missing properties.
240      * 
241      * @return DriverPropertyInfo the property infos; never null but possibly empty
242      */
243     public DriverPropertyInfo[] getPropertyInfos( ) {
244 		List<DriverPropertyInfo> results = new ArrayList<DriverPropertyInfo>();
245 		
246 		addUrlPropertyInfo(results);
247 		addUserNamePropertyInfo(results);
248 		addPasswordPropertyInfo(results);
249 		addWorkspacePropertyInfo(results);
250 		addRepositoryNamePropertyInfo(results);
251 		
252 		return results.toArray(new DriverPropertyInfo[results.size()]);
253     }
254  
255     protected void addUrlPropertyInfo(List<DriverPropertyInfo> results) {
256 		if (getUrl() == null) {
257 		    DriverPropertyInfo info = new DriverPropertyInfo(
258 			    JdbcI18n.urlPropertyName.text(), null);
259 		    info.description = JdbcI18n.urlPropertyDescription
260 			    .text(this.getEffectiveUrl(), getUrlExample());
261 		    info.required = true;
262 		    info.choices = new String[] { getUrlExample() };
263 		    results.add(info);
264 		}
265     }
266     
267     protected void addUserNamePropertyInfo(List<DriverPropertyInfo> results) {
268 		if (getUsername() == null) {
269 		    DriverPropertyInfo info = new DriverPropertyInfo(
270 			    JdbcI18n.usernamePropertyName.text(), null);
271 		    info.description = JdbcI18n.usernamePropertyDescription.text();
272 		    info.required = false;
273 		    info.choices = null;
274 		    results.add(info);
275 		}
276     }
277     
278     protected void addPasswordPropertyInfo(List<DriverPropertyInfo> results) {
279 		if (getPassword() == null) {
280 		    DriverPropertyInfo info = new DriverPropertyInfo(
281 			    JdbcI18n.passwordPropertyName.text(), null);
282 		    info.description = JdbcI18n.passwordPropertyDescription.text();
283 		    info.required = false;
284 		    info.choices = null;
285 		    results.add(info);
286 		}
287     }
288     
289     protected void addWorkspacePropertyInfo(List<DriverPropertyInfo> results) {
290 		if (getWorkspaceName() == null) {
291 		    DriverPropertyInfo info = new DriverPropertyInfo(
292 			    JdbcI18n.workspaceNamePropertyName.text(), null);
293 		    info.description = JdbcI18n.workspaceNamePropertyDescription.text();
294 		    info.required = false;
295 		    info.choices = null;
296 		    results.add(info);
297 		}
298     }
299     
300     protected  void addRepositoryNamePropertyInfo(List<DriverPropertyInfo> results) {
301 		if (getRepositoryName() == null) {
302 				DriverPropertyInfo info = new DriverPropertyInfo(JdbcI18n.repositoryNamePropertyName.text(), null);
303 				info.description = JdbcI18n.repositoryNamePropertyDescription.text();
304 				info.required = true;
305 				info.choices = null;
306 				results.add(info);
307 		}
308     }
309     	
310     /**
311      * The delegate should provide an example of the URL to be used	
312      * @return String url example
313      */
314     public abstract String getUrlExample();
315     
316     /**
317      * The delegate should provide the prefix defined by the {@link JcrDriver}
318      * @return String url prefix
319      */
320     public abstract String getUrlPrefix();
321     
322     /**
323      * Return the credentials based on the user name and password.
324      * 
325      * @return Credentials
326      */
327     public Credentials getCredentials() {
328 		String username = getUsername();
329 		char[] password = getPassword();
330 		if (username != null) {
331 		    return new SimpleCredentials(username, password);
332 		}
333 		return null;
334     }
335     
336 }