1 | /** |
2 | * Copyright 2007 ATG DUST Project |
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 | * |
7 | * You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 |
8 | * |
9 | * Unless required by applicable law or agreed to in writing, software |
10 | * distributed under the License is distributed on an "AS IS" BASIS, |
11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
12 | * See the License for the specific language governing permissions and limitations under the License. |
13 | */ |
14 | package atg.adapter.gsa; |
15 | |
16 | import java.beans.PropertyEditor; |
17 | import java.io.File; |
18 | import java.net.URL; |
19 | import java.sql.SQLException; |
20 | import java.sql.Timestamp; |
21 | import java.util.Date; |
22 | import java.util.HashMap; |
23 | import java.util.Properties; |
24 | import java.util.Random; |
25 | |
26 | import junit.framework.TestCase; |
27 | |
28 | import org.apache.log4j.Logger; |
29 | |
30 | import atg.beans.DynamicPropertyDescriptor; |
31 | import atg.core.util.StringUtils; |
32 | import atg.nucleus.Nucleus; |
33 | import atg.nucleus.servlet.NucleusServlet; |
34 | import atg.repository.MutableRepositoryItem; |
35 | import atg.repository.RepositoryException; |
36 | import atg.repository.RepositoryPropertyDescriptor; |
37 | import atg.service.idgen.IdGenerator; |
38 | import atg.service.idgen.IdGeneratorException; |
39 | import atg.test.util.DBUtils; |
40 | |
41 | /** |
42 | * A basic GSA test which is expected to be extended than used directly. |
43 | * Has several utility methods. |
44 | * @author adwivedi |
45 | * |
46 | */ |
47 | public class GSATest extends TestCase { |
48 | |
49 | private final transient Random random = new Random(); |
50 | |
51 | private static Logger log = Logger.getLogger(GSATest.class); |
52 | |
53 | private HashMap<String, File> mConfigDir = new HashMap<String, File>(); |
54 | /** |
55 | * |
56 | */ |
57 | public GSATest() { |
58 | super(); |
59 | // TODO Auto-generated constructor stub |
60 | } |
61 | /* |
62 | * @see TestCase#setUp() |
63 | */ |
64 | protected void setUp() throws Exception { |
65 | super.setUp(); |
66 | } |
67 | |
68 | /* |
69 | * @see TestCase#tearDown() |
70 | */ |
71 | protected void tearDown() throws Exception { |
72 | super.tearDown(); |
73 | } |
74 | |
75 | /** |
76 | * Constructor for GSATest. |
77 | * @param arg0 |
78 | */ |
79 | public GSATest(String arg0) { |
80 | super(arg0); |
81 | } |
82 | public File getConfigpath() { |
83 | return getConfigpath(null); |
84 | } |
85 | /** |
86 | * Returns the configpath for tests |
87 | * |
88 | * @return |
89 | */ |
90 | public File getConfigpath(String pConfigDirectory) { |
91 | if (mConfigDir.get(pConfigDirectory) == null) { |
92 | String configdirname = "config"; |
93 | String packageName = StringUtils.replace(this.getClass().getPackage() |
94 | .getName(), '.', "/"); |
95 | if (pConfigDirectory != null) |
96 | configdirname = pConfigDirectory; |
97 | |
98 | String configFolder = packageName + "/data/" + configdirname; |
99 | |
100 | URL dataURL = this.getClass().getClassLoader().getResource(configFolder); |
101 | // Mkdir |
102 | if (dataURL == null) { |
103 | URL root = this.getClass().getClassLoader().getResource(packageName); |
104 | |
105 | File f = new File(root.getFile()); |
106 | File f2 = new File(f, "/data/" + configdirname); |
107 | f2.mkdirs(); |
108 | dataURL = this.getClass().getClassLoader().getResource(configFolder); |
109 | } |
110 | |
111 | mConfigDir.put(pConfigDirectory ,new File(dataURL.getFile())); |
112 | } |
113 | System.setProperty("atg.configpath",((File) mConfigDir.get(pConfigDirectory)).getAbsolutePath()); |
114 | return (File) mConfigDir.get(pConfigDirectory); |
115 | } |
116 | |
117 | /** |
118 | * Create a repository in the given configpath using the given repository definitions (Absolute paths) |
119 | * connecting to the db whose properties are specified in pDBProperties @see DBUtils |
120 | * Method pMethodName is invoked with the GSARepository passed to it as a parameter. |
121 | * @param pConfigPathWhereToCreateTheRepository |
122 | * @param definitionFiles |
123 | * @param pDBProperties |
124 | * @param pMethodName |
125 | * @throws Exception |
126 | * @throws Exception |
127 | */ |
128 | protected void setUpAndTest(File pConfigPathWhereToCreateTheRepository, String[] definitionFiles, Properties pDBProperties, String pMethodName) throws Exception{ |
129 | String repositoryComponentPath = "/"+getName()+"Repository"; |
130 | GSATestUtils.getGSATestUtils().initializeMinimalConfigpath(pConfigPathWhereToCreateTheRepository, |
131 | repositoryComponentPath, definitionFiles, pDBProperties, null, null, null, true); |
132 | Nucleus n = startNucleus(pConfigPathWhereToCreateTheRepository); |
133 | GSARepository r = (GSARepository) n.resolveName(repositoryComponentPath); |
134 | try { |
135 | getClass().getMethod(pMethodName, new Class[] { GSARepository.class }) |
136 | .invoke(this, new Object[] { r }); |
137 | } catch (NoSuchMethodError e) { |
138 | throw new AssertionError("Please declare a method with name "+pMethodName + " in your class. It must take an atg.adapter.gsa.GSARepository as the only parameter."); |
139 | } |
140 | finally{ |
141 | // if it were null a NPE would have occurred at the earlier dereference |
142 | //if(n != null) |
143 | n.stopService(); |
144 | } |
145 | } |
146 | |
147 | |
148 | /** |
149 | * Createa a file using reasonable defaults. |
150 | * Your definition file should exist in the same package as the test and should be |
151 | * names <test_name>Repository.xml. Configpath is assumed to be what is returned |
152 | * |
153 | * @param pMethodName |
154 | * @throws Exception |
155 | * @throws Exception |
156 | */ |
157 | protected void setUpAndTest(String pMethodName) throws Exception{ |
158 | File configPathWhereToCreateTheRepository = getConfigpath(null); |
159 | String packageName = StringUtils.replace(this.getClass().getPackage() |
160 | .getName(), '.', "/"); |
161 | String fileName = packageName+"/"+getName()+"Repository.xml"; |
162 | URL defaultDefinitionFile = getClass().getResource("/"+fileName); |
163 | if(defaultDefinitionFile == null )throw new AssertionError("DUDE, I need a file called : "+ fileName +" to start a GSA repository from. "); |
164 | String[] definitionFiles = new String[]{fileName}; |
165 | Properties DBProperties = DBUtils.getHSQLDBInMemoryDBConnection(); |
166 | setUpAndTest(configPathWhereToCreateTheRepository, |
167 | definitionFiles, DBProperties,pMethodName); |
168 | } |
169 | |
170 | /** |
171 | * Starts Nucleus using the given config directory |
172 | * @param configpath |
173 | * @return |
174 | */ |
175 | public static Nucleus startNucleus(File configpath) { |
176 | |
177 | return startNucleus(configpath.getAbsolutePath()); |
178 | } |
179 | /** |
180 | * Starts Nucleus given an array of configpath entries |
181 | * @param configpathStr |
182 | * @return |
183 | */ |
184 | public static Nucleus startNucleus(String configpathStr) { |
185 | System.setProperty("atg.dynamo.license.read", "true"); |
186 | System.setProperty("atg.license.read", "true"); |
187 | NucleusServlet.addNamingFactoriesAndProtocolHandlers(); |
188 | return Nucleus.startNucleus(new String[] {configpathStr}); |
189 | } |
190 | /** |
191 | * @param dbName |
192 | * @return |
193 | * @throws Exception |
194 | * @throws SQLException |
195 | */ |
196 | protected DBUtils initDB(Properties props) throws Exception, SQLException { |
197 | DBUtils db = new DBUtils(props.getProperty("URL"),props.getProperty("driver"),props.getProperty("user"),props.getProperty("password")); |
198 | return db; |
199 | } |
200 | |
201 | /** |
202 | * A Dummy test so smokestack won't report this |
203 | * class as a failure. |
204 | * It expects that all *Test.class files have |
205 | * at least one test. |
206 | * |
207 | */ |
208 | public final void testDummy() { |
209 | |
210 | } |
211 | /** |
212 | * @param pGSARepository |
213 | * @param descName |
214 | * @return |
215 | * @throws RepositoryException |
216 | */ |
217 | protected MutableRepositoryItem createDummyItem(GSARepository pGSARepository, String descName, String pID) throws RepositoryException { |
218 | GSAItemDescriptor descriptor = (GSAItemDescriptor) pGSARepository |
219 | .getItemDescriptor(descName); |
220 | MutableRepositoryItem item = null; |
221 | boolean compoundPrimaryKey = descriptor.getPrimaryTable().getIdColumnCount() > 1; |
222 | if(pID == null || pID.trim().length() == 0){ |
223 | if(compoundPrimaryKey){ |
224 | item = pGSARepository.createItem(getNewCompoundId(pGSARepository, descriptor), descName); |
225 | } |
226 | else |
227 | item = pGSARepository.createItem(descName); |
228 | } |
229 | else{ |
230 | item= pGSARepository.createItem(pID, descName); |
231 | } |
232 | RepositoryPropertyDescriptor[] propDescriptors = (RepositoryPropertyDescriptor[]) descriptor |
233 | .getPropertyDescriptors(); |
234 | for (int j = 0; j < propDescriptors.length; j++) { |
235 | RepositoryPropertyDescriptor propertyDescriptor = propDescriptors[j]; |
236 | if (propertyDescriptor.isWritable() |
237 | && !propertyDescriptor.isIdProperty() |
238 | && propertyDescriptor.isRequired()) { |
239 | if (propertyDescriptor.isCollectionOrMap()) { |
240 | } else { |
241 | |
242 | Object dummyPropertyValue = generateDummyValue(propertyDescriptor); |
243 | if (dummyPropertyValue != null) { |
244 | item.setPropertyValue(propertyDescriptor.getName(), |
245 | dummyPropertyValue); |
246 | } |
247 | } |
248 | } |
249 | } |
250 | return item; |
251 | } |
252 | /** |
253 | * Get a id suitable for creating items of this type. We use out |
254 | * <code>Repository</code>'s <code>IdGenerator</code>. |
255 | * |
256 | * @return a new id, which is unique across all items in this |
257 | * repository with this item descriptor. |
258 | * @exception RepositoryException if there is trouble creating the id |
259 | **/ |
260 | protected GSAId getNewCompoundId(GSARepository r, GSAItemDescriptor desc) throws RepositoryException { |
261 | // make sure we have a repository |
262 | if (r == null) |
263 | return null; |
264 | |
265 | // get the generator to use |
266 | IdGenerator gen = r.getIdGenerator(); |
267 | if (gen == null) |
268 | return null; |
269 | |
270 | Class<?>[] types = desc.getIdTypes(); |
271 | String[] idSpaceNames = desc.getIdSpaceNames(); |
272 | Object[] newId = new Object[types.length]; |
273 | |
274 | if (idSpaceNames.length != types.length) |
275 | throw new RepositoryException("No ID SPACES ! "+ desc.getItemDescriptorName()); |
276 | |
277 | // generate an id in our id space and return it |
278 | try |
279 | { |
280 | for (int i=0;i<types.length;i++) { |
281 | if (types[i] == String.class) { |
282 | if(i > 0) |
283 | newId[i] = "dummyIdPart"; |
284 | else |
285 | newId[i] = gen.generateStringId(idSpaceNames[i]); |
286 | } |
287 | else |
288 | { |
289 | long val = gen.generateLongId(idSpaceNames[i]); |
290 | if (types[i] == Long.class) |
291 | newId[i] = Long.valueOf(val); |
292 | else if (types[i] == Float.class) |
293 | newId[i] = Float.valueOf((float) val); |
294 | else if (types[i] == Double.class) |
295 | newId[i] = Double.valueOf((float) val); |
296 | else if (types[i] == java.sql.Timestamp.class) |
297 | newId[i] = new java.sql.Timestamp(val); |
298 | else if (types[i] == java.util.Date.class) |
299 | newId[i] = new java.util.Date(val); |
300 | else |
301 | newId[i] = Integer.valueOf((int)val); |
302 | } |
303 | } |
304 | } |
305 | catch (IdGeneratorException ie) |
306 | { |
307 | throw new RepositoryException(ie); |
308 | } |
309 | |
310 | return desc.generateGSAId(newId); |
311 | } |
312 | |
313 | @SuppressWarnings("unchecked") |
314 | protected Object generateDummyValue(RepositoryPropertyDescriptor propertyDescriptor) { |
315 | if (getEnumeratedValues(propertyDescriptor) != null) { |
316 | return null;// ignore enums for now. |
317 | } |
318 | |
319 | if (propertyDescriptor.getPropertyType().isAssignableFrom( |
320 | java.lang.String.class)) { |
321 | return generateString(); |
322 | } else if (propertyDescriptor.getPropertyType().isAssignableFrom( |
323 | java.lang.Integer.class)) { |
324 | return generateInteger(); |
325 | } else if (propertyDescriptor.getPropertyType().isAssignableFrom( |
326 | java.lang.Boolean.class)) { |
327 | return generateBoolean(); |
328 | } else if (propertyDescriptor.getPropertyType().isAssignableFrom( |
329 | java.lang.Byte.class)) { |
330 | return generateByte(); |
331 | } else if (propertyDescriptor.getPropertyType().isAssignableFrom( |
332 | java.lang.Short.class)) { |
333 | return generateShort(); |
334 | } else if (propertyDescriptor.getPropertyType().isAssignableFrom( |
335 | java.lang.Long.class)) { |
336 | return generateLong(); |
337 | } else if (propertyDescriptor.getPropertyType().isAssignableFrom( |
338 | java.lang.Float.class)) { |
339 | return generateFloat(); |
340 | } else if (propertyDescriptor.getPropertyType().isAssignableFrom( |
341 | java.lang.Double.class)) { |
342 | return generateDouble(); |
343 | } else if (propertyDescriptor.getPropertyType().isAssignableFrom( |
344 | (new byte[0]).getClass()))//BINARY |
345 | { |
346 | return null; |
347 | // return generateBinary(); |
348 | } else if (propertyDescriptor.getPropertyType().isAssignableFrom( |
349 | java.sql.Timestamp.class)) { |
350 | return generateTimestamp(); |
351 | } else if (propertyDescriptor.getPropertyType().isAssignableFrom( |
352 | java.sql.Date.class)) { |
353 | return generateDate(); |
354 | } |
355 | return null; |
356 | |
357 | } |
358 | /** |
359 | * |
360 | * Returns the set of enumerated values, or null if there are none |
361 | **/ |
362 | String[] getEnumeratedValues(DynamicPropertyDescriptor pDescriptor) { |
363 | if(pDescriptor == null) return null; |
364 | PropertyEditor pe = getPropertyEditor(pDescriptor); |
365 | String[] ret = (pe == null) ? null : pe.getTags(); |
366 | |
367 | // make sure it's not just a boolean value |
368 | Class<?> type = pDescriptor.getPropertyType(); |
369 | if ((type == Boolean.class || type == Boolean.TYPE) |
370 | && ret != null |
371 | && ret.length == 2 |
372 | && (("true".equals(ret[0]) && "false".equals(ret[1])) || ("false" |
373 | .equals(ret[0]) && "true".equals(ret[1])))) { |
374 | return null; |
375 | } else { |
376 | return ret; |
377 | } |
378 | } |
379 | /** |
380 | * |
381 | * Returns an instance of the property editor, null if there is no |
382 | * property editor |
383 | **/ |
384 | PropertyEditor getPropertyEditor(DynamicPropertyDescriptor pDescriptor) { |
385 | if(pDescriptor == null ) return null; |
386 | Class<?> peclass = pDescriptor.getPropertyEditorClass(); |
387 | if (peclass == null) { |
388 | return pDescriptor.getUIPropertyEditor(); |
389 | } else { |
390 | Object peinst = null; |
391 | try { |
392 | peinst = peclass.newInstance(); |
393 | } catch (InstantiationException e) { |
394 | log.error("Error: ", e); |
395 | } catch (IllegalAccessException e) { |
396 | log.error("Error: ", e); |
397 | } |
398 | if (peinst instanceof PropertyEditor) { |
399 | return (PropertyEditor) peinst; |
400 | } else { |
401 | return null; |
402 | } |
403 | } |
404 | } |
405 | /** |
406 | * @return |
407 | */ |
408 | private Object generateDate() { |
409 | return new Date(System.currentTimeMillis()); |
410 | } |
411 | /** |
412 | * @return |
413 | */ |
414 | private Object generateTimestamp() { |
415 | return new Timestamp(System.currentTimeMillis()); |
416 | } |
417 | // /** |
418 | // * @return |
419 | // */ |
420 | // private Object generateBinary() { |
421 | // byte[] bytes = new byte[100]; |
422 | // Random random = new Random(); |
423 | // random.nextBytes(bytes); |
424 | // return bytes; |
425 | // } |
426 | /** |
427 | * @return |
428 | */ |
429 | private Object generateDouble() { |
430 | return new Double(random.nextDouble()); |
431 | } |
432 | /** |
433 | * @return |
434 | */ |
435 | private Object generateInteger() { |
436 | return Integer.valueOf(random.nextInt(32768)); |
437 | } |
438 | /** |
439 | * @return |
440 | */ |
441 | private Object generateFloat() { |
442 | return new Float(random.nextFloat()); |
443 | } |
444 | /** |
445 | * @return |
446 | */ |
447 | private Object generateLong() { |
448 | return Long.valueOf(random.nextInt(32278)); |
449 | } |
450 | /** |
451 | * @return |
452 | */ |
453 | private Object generateShort() { |
454 | return Short.valueOf((short) (random.nextInt(100))); |
455 | } |
456 | /** |
457 | * @return |
458 | */ |
459 | private Object generateByte() { |
460 | byte[] bytes = new byte[1]; |
461 | random.nextBytes(bytes); |
462 | return Byte.valueOf(bytes[0]); |
463 | } |
464 | /** |
465 | * @return |
466 | */ |
467 | private Object generateBoolean() { |
468 | return Boolean.valueOf(random.nextBoolean()); |
469 | } |
470 | /** |
471 | * @return |
472 | */ |
473 | private Object generateString() { |
474 | |
475 | return "DUMMY STRING " + generateInteger(); |
476 | } |
477 | |
478 | |
479 | } |