1 | /* |
2 | |
3 | Derby - Class org.apache.derby.impl.sql.conn.GenericLanguageConnectionFactory |
4 | |
5 | Copyright 1997, 2004 The Apache Software Foundation or its licensors, as applicable. |
6 | |
7 | Licensed under the Apache License, Version 2.0 (the "License"); |
8 | you may not use this file except in compliance with the License. |
9 | You may obtain a copy of the License at |
10 | |
11 | http://www.apache.org/licenses/LICENSE-2.0 |
12 | |
13 | Unless required by applicable law or agreed to in writing, software |
14 | distributed under the License is distributed on an "AS IS" BASIS, |
15 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
16 | See the License for the specific language governing permissions and |
17 | limitations under the License. |
18 | |
19 | */ |
20 | |
21 | package org.apache.derby.impl.sql.conn; |
22 | |
23 | import org.apache.derby.iapi.reference.JDBC20Translation; |
24 | import org.apache.derby.iapi.reference.JDBC30Translation; |
25 | |
26 | import org.apache.derby.iapi.sql.conn.LanguageConnectionFactory; |
27 | import org.apache.derby.iapi.sql.conn.LanguageConnectionContext; |
28 | import org.apache.derby.iapi.sql.compile.CompilerContext; |
29 | |
30 | import org.apache.derby.iapi.sql.LanguageFactory; |
31 | import org.apache.derby.impl.sql.GenericStatement; |
32 | |
33 | import org.apache.derby.impl.sql.conn.CachedStatement; |
34 | |
35 | import org.apache.derby.iapi.services.uuid.UUIDFactory; |
36 | import org.apache.derby.iapi.services.compiler.JavaFactory; |
37 | import org.apache.derby.iapi.services.loader.ClassFactory; |
38 | |
39 | import org.apache.derby.iapi.db.Database; |
40 | |
41 | import org.apache.derby.iapi.store.access.TransactionController; |
42 | |
43 | import org.apache.derby.iapi.sql.compile.TypeCompilerFactory; |
44 | |
45 | import org.apache.derby.iapi.error.StandardException; |
46 | |
47 | import org.apache.derby.iapi.sql.compile.NodeFactory; |
48 | import org.apache.derby.iapi.sql.compile.Parser; |
49 | |
50 | import org.apache.derby.iapi.sql.Activation; |
51 | |
52 | import org.apache.derby.iapi.store.access.AccessFactory; |
53 | import org.apache.derby.iapi.services.property.PropertyFactory; |
54 | |
55 | import org.apache.derby.iapi.sql.Statement; |
56 | import org.apache.derby.iapi.sql.compile.OptimizerFactory; |
57 | import org.apache.derby.iapi.sql.dictionary.DataDictionary; |
58 | import org.apache.derby.iapi.types.DataValueFactory; |
59 | import org.apache.derby.iapi.sql.execute.ExecutionFactory; |
60 | import org.apache.derby.iapi.sql.dictionary.SchemaDescriptor; |
61 | |
62 | import org.apache.derby.iapi.services.sanity.SanityManager; |
63 | |
64 | import org.apache.derby.iapi.services.monitor.Monitor; |
65 | import org.apache.derby.iapi.services.monitor.ModuleControl; |
66 | import org.apache.derby.iapi.services.monitor.ModuleSupportable; |
67 | import org.apache.derby.iapi.services.monitor.ModuleFactory; |
68 | import org.apache.derby.iapi.services.context.ContextManager; |
69 | |
70 | import org.apache.derby.iapi.services.cache.CacheFactory; |
71 | import org.apache.derby.iapi.services.cache.CacheManager; |
72 | import org.apache.derby.iapi.services.cache.CacheableFactory; |
73 | import org.apache.derby.iapi.services.cache.Cacheable; |
74 | |
75 | import org.apache.derby.iapi.services.property.PropertyUtil; |
76 | import org.apache.derby.iapi.services.property.PropertySetCallback; |
77 | |
78 | import org.apache.derby.iapi.services.i18n.LocaleFinder; |
79 | import org.apache.derby.iapi.reference.SQLState; |
80 | import org.apache.derby.iapi.reference.Property; |
81 | import org.apache.derby.iapi.reference.EngineType; |
82 | |
83 | import java.util.Properties; |
84 | import java.util.Locale; |
85 | import java.util.Dictionary; |
86 | import java.io.Serializable; |
87 | import org.apache.derby.iapi.util.IdUtil; |
88 | import org.apache.derby.iapi.services.daemon.Serviceable; |
89 | import org.apache.derby.iapi.util.StringUtil; |
90 | |
91 | /** |
92 | * LanguageConnectionFactory generates all of the items |
93 | * a language system needs that is specific to a particular |
94 | * connection. Alot of these are other factories. |
95 | * |
96 | * @author ames |
97 | */ |
98 | public class GenericLanguageConnectionFactory |
99 | implements LanguageConnectionFactory, CacheableFactory, PropertySetCallback, ModuleControl, ModuleSupportable { |
100 | |
101 | /* |
102 | fields |
103 | */ |
104 | protected DataDictionary dd; |
105 | private ExecutionFactory ef; |
106 | private OptimizerFactory of; |
107 | private TypeCompilerFactory tcf; |
108 | private DataValueFactory dvf; |
109 | private UUIDFactory uuidFactory; |
110 | private JavaFactory javaFactory; |
111 | private ClassFactory classFactory; |
112 | private NodeFactory nodeFactory; |
113 | private AccessFactory af; |
114 | private PropertyFactory pf; |
115 | |
116 | private int nextLCCInstanceNumber; |
117 | |
118 | /* |
119 | for caching prepared statements |
120 | */ |
121 | private int cacheSize = org.apache.derby.iapi.reference.Property.STATEMENT_CACHE_SIZE_DEFAULT; |
122 | private CacheManager singleStatementCache; |
123 | |
124 | /* |
125 | constructor |
126 | */ |
127 | public GenericLanguageConnectionFactory() { |
128 | } |
129 | |
130 | /* |
131 | LanguageConnectionFactory interface |
132 | */ |
133 | |
134 | /* |
135 | these are the methods that do real work, not just look for factories |
136 | */ |
137 | |
138 | /** |
139 | Get a Statement for the connection |
140 | @param compilationSchema schema |
141 | @param statementText the text for the statement |
142 | @param forReadOnly if concurrency is CONCUR_READ_ONLY |
143 | @return The Statement |
144 | */ |
145 | public Statement getStatement(SchemaDescriptor compilationSchema, String statementText, boolean forReadOnly) |
146 | { |
147 | return new GenericStatement(compilationSchema, statementText, forReadOnly); |
148 | } |
149 | |
150 | |
151 | /** |
152 | Get a LanguageConnectionContext. this holds things |
153 | we want to remember about activity in the language system, |
154 | where this factory holds things that are pretty stable, |
155 | like other factories. |
156 | <p> |
157 | The returned LanguageConnectionContext is intended for use |
158 | only by the connection that requested it. |
159 | |
160 | @return a language connection context for the context stack. |
161 | @exception StandardException the usual -- for the subclass |
162 | */ |
163 | |
164 | public LanguageConnectionContext newLanguageConnectionContext( |
165 | ContextManager cm, |
166 | TransactionController tc, |
167 | LanguageFactory lf, |
168 | Database db, |
169 | String userName, |
170 | String drdaID, |
171 | String dbname) throws StandardException { |
172 | |
173 | pushDataDictionaryContext(cm); |
174 | |
175 | return new GenericLanguageConnectionContext(cm, |
176 | tc, |
177 | lf, |
178 | this, |
179 | db, |
180 | userName, |
181 | getNextLCCInstanceNumber(), |
182 | drdaID, |
183 | dbname); |
184 | } |
185 | |
186 | public Cacheable newCacheable(CacheManager cm) { |
187 | return new CachedStatement(); |
188 | } |
189 | |
190 | /* |
191 | these methods all look for factories that we booted. |
192 | */ |
193 | |
194 | /** |
195 | Get the UUIDFactory to use with this language connection |
196 | REMIND: this is only used by the compiler; should there be |
197 | a compiler module control class to boot compiler-only stuff? |
198 | */ |
199 | public UUIDFactory getUUIDFactory() |
200 | { |
201 | return uuidFactory; |
202 | } |
203 | |
204 | /** |
205 | Get the ClassFactory to use with this language connection |
206 | */ |
207 | public ClassFactory getClassFactory() |
208 | { |
209 | return classFactory; |
210 | } |
211 | |
212 | /** |
213 | Get the JavaFactory to use with this language connection |
214 | REMIND: this is only used by the compiler; should there be |
215 | a compiler module control class to boot compiler-only stuff? |
216 | */ |
217 | public JavaFactory getJavaFactory() |
218 | { |
219 | return javaFactory; |
220 | } |
221 | |
222 | /** |
223 | Get the NodeFactory to use with this language connection |
224 | REMIND: is this only used by the compiler? |
225 | */ |
226 | public NodeFactory getNodeFactory() |
227 | { |
228 | return nodeFactory; |
229 | } |
230 | |
231 | /** |
232 | Get the ExecutionFactory to use with this language connection |
233 | */ |
234 | public ExecutionFactory getExecutionFactory() { |
235 | return ef; |
236 | } |
237 | |
238 | /** |
239 | Get the AccessFactory to use with this language connection |
240 | */ |
241 | public AccessFactory getAccessFactory() |
242 | { |
243 | return af; |
244 | } |
245 | |
246 | /** |
247 | Get the PropertyFactory to use with this language connection |
248 | */ |
249 | public PropertyFactory getPropertyFactory() |
250 | { |
251 | return pf; |
252 | } |
253 | |
254 | /** |
255 | Get the OptimizerFactory to use with this language connection |
256 | */ |
257 | public OptimizerFactory getOptimizerFactory() { |
258 | return of; |
259 | } |
260 | /** |
261 | Get the TypeCompilerFactory to use with this language connection |
262 | */ |
263 | public TypeCompilerFactory getTypeCompilerFactory() { |
264 | return tcf; |
265 | } |
266 | |
267 | /** |
268 | Get the DataValueFactory to use with this language connection |
269 | */ |
270 | public DataValueFactory getDataValueFactory() { |
271 | return dvf; |
272 | } |
273 | |
274 | protected void pushDataDictionaryContext(ContextManager cm) { |
275 | // we make sure there is a data dictionary context in place. |
276 | dd.pushDataDictionaryContext(cm); |
277 | } |
278 | |
279 | /* |
280 | ModuleControl interface |
281 | */ |
282 | |
283 | /** |
284 | this implementation will not support caching of statements. |
285 | */ |
286 | public boolean canSupport(Properties startParams) { |
287 | |
288 | return Monitor.isDesiredType( startParams, EngineType.STANDALONE_DB); |
289 | } |
290 | |
291 | private int statementCacheSize(Properties startParams) |
292 | { |
293 | String wantCacheProperty = null; |
294 | |
295 | wantCacheProperty = |
296 | PropertyUtil.getPropertyFromSet(startParams, org.apache.derby.iapi.reference.Property.STATEMENT_CACHE_SIZE); |
297 | |
298 | if (SanityManager.DEBUG) |
299 | SanityManager.DEBUG("StatementCacheInfo", "Cacheing implementation chosen if null or 0<"+wantCacheProperty); |
300 | |
301 | if (wantCacheProperty != null) { |
302 | try { |
303 | cacheSize = Integer.parseInt(wantCacheProperty); |
304 | } catch (NumberFormatException nfe) { |
305 | cacheSize = org.apache.derby.iapi.reference.Property.STATEMENT_CACHE_SIZE_DEFAULT; |
306 | } |
307 | } |
308 | |
309 | return cacheSize; |
310 | } |
311 | |
312 | /** |
313 | * Start-up method for this instance of the language connection factory. |
314 | * Note these are expected to be booted relative to a Database. |
315 | * |
316 | * @param startParams The start-up parameters (ignored in this case) |
317 | * |
318 | * @exception StandardException Thrown on failure to boot |
319 | */ |
320 | public void boot(boolean create, Properties startParams) |
321 | throws StandardException { |
322 | |
323 | dvf = (DataValueFactory) Monitor.bootServiceModule(create, this, org.apache.derby.iapi.reference.ClassName.DataValueFactory, startParams); |
324 | javaFactory = (JavaFactory) Monitor.startSystemModule(org.apache.derby.iapi.reference.Module.JavaFactory); |
325 | uuidFactory = Monitor.getMonitor().getUUIDFactory(); |
326 | classFactory = (ClassFactory) Monitor.getServiceModule(this, org.apache.derby.iapi.reference.Module.ClassFactory); |
327 | if (classFactory == null) |
328 | classFactory = (ClassFactory) Monitor.findSystemModule(org.apache.derby.iapi.reference.Module.ClassFactory); |
329 | |
330 | bootDataDictionary(create, startParams); |
331 | |
332 | //set the property validation module needed to do propertySetCallBack |
333 | //register and property validation |
334 | setValidation(); |
335 | |
336 | setStore(); |
337 | |
338 | ef = (ExecutionFactory) Monitor.bootServiceModule(create, this, ExecutionFactory.MODULE, startParams); |
339 | of = (OptimizerFactory) Monitor.bootServiceModule(create, this, OptimizerFactory.MODULE, startParams); |
340 | tcf = |
341 | (TypeCompilerFactory) Monitor.startSystemModule(TypeCompilerFactory.MODULE); |
342 | nodeFactory = (NodeFactory) Monitor.bootServiceModule(create, this, NodeFactory.MODULE, startParams); |
343 | |
344 | // If the system supports statement caching boot the CacheFactory module. |
345 | int cacheSize = statementCacheSize(startParams); |
346 | if (cacheSize > 0) { |
347 | CacheFactory cacheFactory = (CacheFactory) Monitor.startSystemModule(org.apache.derby.iapi.reference.Module.CacheFactory); |
348 | singleStatementCache = cacheFactory.newCacheManager(this, |
349 | "StatementCache", |
350 | cacheSize/4, |
351 | cacheSize); |
352 | } |
353 | |
354 | } |
355 | |
356 | protected void bootDataDictionary(boolean create, Properties startParams) throws StandardException { |
357 | dd = (DataDictionary) Monitor.bootServiceModule(create, this, DataDictionary.MODULE, startParams); |
358 | } |
359 | |
360 | /** |
361 | * returns the statement cache that this connection should use; currently |
362 | * there is a statement cache per connection. |
363 | */ |
364 | |
365 | |
366 | public CacheManager getStatementCache() |
367 | { |
368 | return singleStatementCache; |
369 | } |
370 | |
371 | /** |
372 | * Stop this module. In this case, nothing needs to be done. |
373 | */ |
374 | public void stop() { |
375 | } |
376 | |
377 | /* |
378 | ** Methods of PropertySetCallback |
379 | */ |
380 | |
381 | public void init(boolean dbOnly, Dictionary p) { |
382 | // not called yet ... |
383 | } |
384 | |
385 | /** |
386 | @see PropertySetCallback#validate |
387 | @exception StandardException Thrown on error. |
388 | */ |
389 | public boolean validate(String key, |
390 | Serializable value, |
391 | Dictionary p) |
392 | throws StandardException { |
393 | if (value == null) |
394 | return true; |
395 | else if (key.equals(Property.DEFAULT_CONNECTION_MODE_PROPERTY)) |
396 | { |
397 | String value_s = (String)value; |
398 | if (value_s != null && |
399 | !StringUtil.SQLEqualsIgnoreCase(value_s, Property.NO_ACCESS) && |
400 | !StringUtil.SQLEqualsIgnoreCase(value_s, Property.READ_ONLY_ACCESS) && |
401 | !StringUtil.SQLEqualsIgnoreCase(value_s, Property.FULL_ACCESS)) |
402 | throw StandardException.newException(SQLState.AUTH_INVALID_AUTHORIZATION_PROPERTY, key, value_s); |
403 | |
404 | return true; |
405 | } |
406 | else if (key.equals(Property.READ_ONLY_ACCESS_USERS_PROPERTY) || |
407 | key.equals(Property.FULL_ACCESS_USERS_PROPERTY)) |
408 | { |
409 | String value_s = (String)value; |
410 | |
411 | /** Parse the new userIdList to verify its syntax. */ |
412 | String[] newList_a; |
413 | try {newList_a = IdUtil.parseIdList(value_s);} |
414 | catch (StandardException se) { |
415 | throw StandardException.newException(SQLState.AUTH_INVALID_AUTHORIZATION_PROPERTY, se, key,value_s); |
416 | } |
417 | |
418 | /** Check the new list userIdList for duplicates. */ |
419 | String dups = IdUtil.dups(newList_a); |
420 | if (dups != null) throw StandardException.newException(SQLState.AUTH_DUPLICATE_USERS, key,dups); |
421 | |
422 | /** Check for users with both read and full access permission. */ |
423 | String[] otherList_a; |
424 | String otherList; |
425 | if (key.equals(Property.READ_ONLY_ACCESS_USERS_PROPERTY)) |
426 | otherList = (String)p.get(Property.FULL_ACCESS_USERS_PROPERTY); |
427 | else |
428 | otherList = (String)p.get(Property.READ_ONLY_ACCESS_USERS_PROPERTY); |
429 | otherList_a = IdUtil.parseIdList(otherList); |
430 | String both = IdUtil.intersect(newList_a,otherList_a); |
431 | if (both != null) throw StandardException.newException(SQLState.AUTH_USER_IN_READ_AND_WRITE_LISTS, both); |
432 | |
433 | return true; |
434 | } |
435 | |
436 | return false; |
437 | } |
438 | /** @see PropertySetCallback#apply */ |
439 | public Serviceable apply(String key, |
440 | Serializable value, |
441 | Dictionary p) |
442 | { |
443 | return null; |
444 | } |
445 | /** @see PropertySetCallback#map */ |
446 | public Serializable map(String key, Serializable value, Dictionary p) |
447 | { |
448 | return null; |
449 | } |
450 | |
451 | protected void setValidation() throws StandardException { |
452 | pf = (PropertyFactory) Monitor.findServiceModule(this, |
453 | org.apache.derby.iapi.reference.Module.PropertyFactory); |
454 | pf.addPropertySetNotification(this); |
455 | } |
456 | |
457 | protected void setStore() throws StandardException { |
458 | af = (AccessFactory) Monitor.findServiceModule(this,AccessFactory.MODULE); |
459 | } |
460 | |
461 | public Parser newParser(CompilerContext cc) |
462 | { |
463 | return new org.apache.derby.impl.sql.compile.ParserImpl(cc); |
464 | } |
465 | |
466 | // Class methods |
467 | |
468 | /** |
469 | * Get the instance # for the next LCC. |
470 | * (Useful for logStatementText=true output. |
471 | * |
472 | * @return instance # of next LCC. |
473 | */ |
474 | protected synchronized int getNextLCCInstanceNumber() |
475 | { |
476 | return nextLCCInstanceNumber++; |
477 | } |
478 | } |