Source Code Cross Referenced for PluginCreateRule.java in  » Library » Apache-commons-digester-1.8-src » org » apache » commons » digester » plugins » Java Source Code / Java DocumentationJava Source Code and Java Documentation

Java Source Code / Java Documentation
1. 6.0 JDK Core
2. 6.0 JDK Modules
3. 6.0 JDK Modules com.sun
4. 6.0 JDK Modules com.sun.java
5. 6.0 JDK Modules sun
6. 6.0 JDK Platform
7. Ajax
8. Apache Harmony Java SE
9. Aspect oriented
10. Authentication Authorization
11. Blogger System
12. Build
13. Byte Code
14. Cache
15. Chart
16. Chat
17. Code Analyzer
18. Collaboration
19. Content Management System
20. Database Client
21. Database DBMS
22. Database JDBC Connection Pool
23. Database ORM
24. Development
25. EJB Server geronimo
26. EJB Server GlassFish
27. EJB Server JBoss 4.2.1
28. EJB Server resin 3.1.5
29. ERP CRM Financial
30. ESB
31. Forum
32. GIS
33. Graphic Library
34. Groupware
35. HTML Parser
36. IDE
37. IDE Eclipse
38. IDE Netbeans
39. Installer
40. Internationalization Localization
41. Inversion of Control
42. Issue Tracking
43. J2EE
44. JBoss
45. JMS
46. JMX
47. Library
48. Mail Clients
49. Net
50. Parser
51. PDF
52. Portal
53. Profiler
54. Project Management
55. Report
56. RSS RDF
57. Rule Engine
58. Science
59. Scripting
60. Search Engine
61. Security
62. Sevlet Container
63. Source Control
64. Swing Library
65. Template Engine
66. Test Coverage
67. Testing
68. UML
69. Web Crawler
70. Web Framework
71. Web Mail
72. Web Server
73. Web Services
74. Web Services apache cxf 2.0.1
75. Web Services AXIS2
76. Wiki Engine
77. Workflow Engines
78. XML
79. XML UI
Java
Java Tutorial
Java Open Source
Jar File Download
Java Articles
Java Products
Java by API
Photoshop Tutorials
Maya Tutorials
Flash Tutorials
3ds-Max Tutorials
Illustrator Tutorials
GIMP Tutorials
C# / C Sharp
C# / CSharp Tutorial
C# / CSharp Open Source
ASP.Net
ASP.NET Tutorial
JavaScript DHTML
JavaScript Tutorial
JavaScript Reference
HTML / CSS
HTML CSS Reference
C / ANSI-C
C Tutorial
C++
C++ Tutorial
Ruby
PHP
Python
Python Tutorial
Python Open Source
SQL Server / T-SQL
SQL Server / T-SQL Tutorial
Oracle PL / SQL
Oracle PL/SQL Tutorial
PostgreSQL
SQL / MySQL
MySQL Tutorial
VB.Net
VB.Net Tutorial
Flash / Flex / ActionScript
VBA / Excel / Access / Word
XML
XML Tutorial
Microsoft Office PowerPoint 2007 Tutorial
Microsoft Office Excel 2007 Tutorial
Microsoft Office Word 2007 Tutorial
Java Source Code / Java Documentation » Library » Apache commons digester 1.8 src » org.apache.commons.digester.plugins 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


001:        /* $Id: PluginCreateRule.java 471661 2006-11-06 08:09:25Z skitching $
002:         *
003:         * Licensed to the Apache Software Foundation (ASF) under one or more
004:         * contributor license agreements.  See the NOTICE file distributed with
005:         * this work for additional information regarding copyright ownership.
006:         * The ASF licenses this file to You under the Apache License, Version 2.0
007:         * (the "License"); you may not use this file except in compliance with
008:         * the License.  You may obtain a copy of the License at
009:         * 
010:         *      http://www.apache.org/licenses/LICENSE-2.0
011:         * 
012:         * Unless required by applicable law or agreed to in writing, software
013:         * distributed under the License is distributed on an "AS IS" BASIS,
014:         * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
015:         * See the License for the specific language governing permissions and
016:         * limitations under the License.
017:         */
018:
019:        package org.apache.commons.digester.plugins;
020:
021:        import java.util.List;
022:
023:        import org.apache.commons.digester.Rule;
024:        import org.apache.commons.logging.Log;
025:
026:        /**
027:         * Allows the original rules for parsing the configuration file to define
028:         * points at which plugins are allowed, by configuring a PluginCreateRule
029:         * with the appropriate pattern.
030:         *
031:         * @since 1.6
032:         */
033:        public class PluginCreateRule extends Rule implements  InitializableRule {
034:
035:            // see setPluginClassAttribute
036:            private String pluginClassAttrNs = null;
037:            private String pluginClassAttr = null;
038:
039:            // see setPluginIdAttribute
040:            private String pluginIdAttrNs = null;
041:            private String pluginIdAttr = null;
042:
043:            /**
044:             * In order to invoke the addRules method on the plugin class correctly,
045:             * we need to know the pattern which this rule is matched by.
046:             */
047:            private String pattern;
048:
049:            /** A base class that any plugin must derive from. */
050:            private Class baseClass = null;
051:
052:            /**
053:             * Info about optional default plugin to be used if no plugin-id is
054:             * specified in the input data. This can simplify the syntax where one
055:             * particular plugin is usually used.
056:             */
057:            private Declaration defaultPlugin;
058:
059:            /**
060:             * Currently, none of the Rules methods allow exceptions to be thrown.
061:             * Therefore if this class cannot initialise itself properly, it cannot
062:             * cause the digester to stop. Instead, we cache the exception and throw
063:             * it the first time the begin() method is called.
064:             */
065:            private PluginConfigurationException initException;
066:
067:            //-------------------- constructors -------------------------------------
068:
069:            /**
070:             * Create a plugin rule where the user <i>must</i> specify a plugin-class
071:             * or plugin-id.
072:             * 
073:             * @param baseClass is the class which any specified plugin <i>must</i> be
074:             * descended from.
075:             */
076:            public PluginCreateRule(Class baseClass) {
077:                this .baseClass = baseClass;
078:            }
079:
080:            /**
081:             * Create a plugin rule where the user <i>may</i> specify a plugin.
082:             * If the user doesn't specify a plugin, then the default class specified 
083:             * in this constructor is used.
084:             * 
085:             * @param baseClass is the class which any specified plugin <i>must</i> be
086:             * descended from.
087:             * @param dfltPluginClass is the class which will be used if the user
088:             * doesn't specify any plugin-class or plugin-id. This class will have
089:             * custom rules installed for it just like a declared plugin.
090:             */
091:            public PluginCreateRule(Class baseClass, Class dfltPluginClass) {
092:                this .baseClass = baseClass;
093:                if (dfltPluginClass != null) {
094:                    defaultPlugin = new Declaration(dfltPluginClass);
095:                }
096:            }
097:
098:            /**
099:             * Create a plugin rule where the user <i>may</i> specify a plugin.
100:             * If the user doesn't specify a plugin, then the default class specified 
101:             * in this constructor is used.
102:             * 
103:             * @param baseClass is the class which any specified plugin <i>must</i> be
104:             * descended from.
105:             * @param dfltPluginClass is the class which will be used if the user
106:             * doesn't specify any plugin-class or plugin-id. This class will have
107:             * custom rules installed for it just like a declared plugin.
108:             * @param dfltPluginRuleLoader is a RuleLoader instance which knows how
109:             * to load the custom rules associated with this default plugin.
110:             */
111:            public PluginCreateRule(Class baseClass, Class dfltPluginClass,
112:                    RuleLoader dfltPluginRuleLoader) {
113:
114:                this .baseClass = baseClass;
115:                if (dfltPluginClass != null) {
116:                    defaultPlugin = new Declaration(dfltPluginClass,
117:                            dfltPluginRuleLoader);
118:                }
119:            }
120:
121:            //------------------- properties ---------------------------------------
122:
123:            /**
124:             * Sets the xml attribute which the input xml uses to indicate to a 
125:             * PluginCreateRule which class should be instantiated.
126:             * <p>
127:             * See {@link PluginRules#setPluginClassAttribute} for more info.
128:             */
129:            public void setPluginClassAttribute(String namespaceUri,
130:                    String attrName) {
131:                pluginClassAttrNs = namespaceUri;
132:                pluginClassAttr = attrName;
133:            }
134:
135:            /**
136:             * Sets the xml attribute which the input xml uses to indicate to a 
137:             * PluginCreateRule which plugin declaration is being referenced.
138:             * <p>
139:             * See {@link PluginRules#setPluginIdAttribute} for more info.
140:             */
141:            public void setPluginIdAttribute(String namespaceUri,
142:                    String attrName) {
143:                pluginIdAttrNs = namespaceUri;
144:                pluginIdAttr = attrName;
145:            }
146:
147:            //------------------- methods --------------------------------------------
148:
149:            /**
150:             * Invoked after this rule has been added to the set of digester rules,
151:             * associated with the specified pattern. Check all configuration data is
152:             * valid and remember the pattern for later.
153:             * 
154:             * @param matchPattern is the digester match pattern that is associated 
155:             * with this rule instance, eg "root/widget".
156:             * @exception PluginConfigurationException
157:             */
158:            public void postRegisterInit(String matchPattern)
159:                    throws PluginConfigurationException {
160:                Log log = LogUtils.getLogger(digester);
161:                boolean debug = log.isDebugEnabled();
162:                if (debug) {
163:                    log.debug("PluginCreateRule.postRegisterInit"
164:                            + ": rule registered for pattern [" + matchPattern
165:                            + "]");
166:                }
167:
168:                if (digester == null) {
169:                    // We require setDigester to be called before this method.
170:                    // Note that this means that PluginCreateRule cannot be added
171:                    // to a Rules object which has not yet been added to a
172:                    // Digester object.
173:                    initException = new PluginConfigurationException(
174:                            "Invalid invocation of postRegisterInit"
175:                                    + ": digester not set.");
176:                    throw initException;
177:                }
178:
179:                if (pattern != null) {
180:                    // We have been called twice, ie a single instance has been
181:                    // associated with multiple patterns.
182:                    //
183:                    // Generally, Digester Rule instances can be associated with 
184:                    // multiple patterns. However for plugins, this creates some 
185:                    // complications. Some day this may be supported; however for 
186:                    // now we just reject this situation.
187:                    initException = new PluginConfigurationException(
188:                            "A single PluginCreateRule instance has been mapped to"
189:                                    + " multiple patterns; this is not supported.");
190:                    throw initException;
191:                }
192:
193:                if (matchPattern.indexOf('*') != -1) {
194:                    // having wildcards in patterns is extremely difficult to
195:                    // deal with. For now, we refuse to allow this.
196:                    //
197:                    // TODO: check for any chars not valid in xml element name
198:                    // rather than just *.
199:                    //
200:                    // Reasons include:
201:                    // (a) handling recursive plugins, and
202:                    // (b) determining whether one pattern is "below" another,
203:                    //     as done by PluginRules. Without wildcards, "below"
204:                    //     just means startsWith, which is easy to check.
205:                    initException = new PluginConfigurationException(
206:                            "A PluginCreateRule instance has been mapped to"
207:                                    + " pattern ["
208:                                    + matchPattern
209:                                    + "]."
210:                                    + " This pattern includes a wildcard character."
211:                                    + " This is not supported by the plugin architecture.");
212:                    throw initException;
213:                }
214:
215:                if (baseClass == null) {
216:                    baseClass = Object.class;
217:                }
218:
219:                PluginRules rules = (PluginRules) digester.getRules();
220:                PluginManager pm = rules.getPluginManager();
221:
222:                // check default class is valid
223:                if (defaultPlugin != null) {
224:                    if (!baseClass.isAssignableFrom(defaultPlugin
225:                            .getPluginClass())) {
226:                        initException = new PluginConfigurationException(
227:                                "Default class ["
228:                                        + defaultPlugin.getPluginClass()
229:                                                .getName()
230:                                        + "] does not inherit from ["
231:                                        + baseClass.getName() + "].");
232:                        throw initException;
233:                    }
234:
235:                    try {
236:                        defaultPlugin.init(digester, pm);
237:
238:                    } catch (PluginException pwe) {
239:
240:                        throw new PluginConfigurationException(
241:                                pwe.getMessage(), pwe.getCause());
242:                    }
243:                }
244:
245:                // remember the pattern for later
246:                pattern = matchPattern;
247:
248:                if (pluginClassAttr == null) {
249:                    // the user hasn't set explicit xml attr names on this rule,
250:                    // so fetch the default values
251:                    pluginClassAttrNs = rules.getPluginClassAttrNs();
252:                    pluginClassAttr = rules.getPluginClassAttr();
253:
254:                    if (debug) {
255:                        log
256:                                .debug("init: pluginClassAttr set to per-digester values ["
257:                                        + "ns="
258:                                        + pluginClassAttrNs
259:                                        + ", name="
260:                                        + pluginClassAttr + "]");
261:                    }
262:                } else {
263:                    if (debug) {
264:                        log
265:                                .debug("init: pluginClassAttr set to rule-specific values ["
266:                                        + "ns="
267:                                        + pluginClassAttrNs
268:                                        + ", name="
269:                                        + pluginClassAttr + "]");
270:                    }
271:                }
272:
273:                if (pluginIdAttr == null) {
274:                    // the user hasn't set explicit xml attr names on this rule,
275:                    // so fetch the default values
276:                    pluginIdAttrNs = rules.getPluginIdAttrNs();
277:                    pluginIdAttr = rules.getPluginIdAttr();
278:
279:                    if (debug) {
280:                        log
281:                                .debug("init: pluginIdAttr set to per-digester values ["
282:                                        + "ns="
283:                                        + pluginIdAttrNs
284:                                        + ", name="
285:                                        + pluginIdAttr + "]");
286:                    }
287:                } else {
288:                    if (debug) {
289:                        log
290:                                .debug("init: pluginIdAttr set to rule-specific values ["
291:                                        + "ns="
292:                                        + pluginIdAttrNs
293:                                        + ", name="
294:                                        + pluginIdAttr + "]");
295:                    }
296:                }
297:            }
298:
299:            /**
300:             * Invoked when the Digester matches this rule against an xml element.
301:             * <p>
302:             * A new instance of the target class is created, and pushed onto the
303:             * stack. A new "private" PluginRules object is then created and set as
304:             * the digester's default Rules object. Any custom rules associated with
305:             * the plugin class are then loaded into that new Rules object.
306:             * Finally, any custom rules that are associated with the current pattern
307:             * (such as SetPropertiesRules) have their begin methods executed.
308:             * 
309:             * @param namespace 
310:             * @param name 
311:             * @param attributes
312:             *
313:             * @throws ClassNotFoundException
314:             * @throws PluginInvalidInputException
315:             * @throws PluginConfigurationException
316:             */
317:            public void begin(String namespace, String name,
318:                    org.xml.sax.Attributes attributes)
319:                    throws java.lang.Exception {
320:                Log log = digester.getLogger();
321:                boolean debug = log.isDebugEnabled();
322:                if (debug) {
323:                    log.debug("PluginCreateRule.begin" + ": pattern=["
324:                            + pattern + "]" + " match=[" + digester.getMatch()
325:                            + "]");
326:                }
327:
328:                if (initException != null) {
329:                    // we had a problem during initialisation that we could
330:                    // not report then; report it now.
331:                    throw initException;
332:                }
333:
334:                // load any custom rules associated with the plugin
335:                PluginRules oldRules = (PluginRules) digester.getRules();
336:                PluginManager pluginManager = oldRules.getPluginManager();
337:                Declaration currDeclaration = null;
338:
339:                String pluginClassName;
340:                if (pluginClassAttrNs == null) {
341:                    // Yep, this is ugly.
342:                    //
343:                    // In a namespace-aware parser, the one-param version will 
344:                    // return attributes with no namespace.
345:                    //
346:                    // In a non-namespace-aware parser, the two-param version will 
347:                    // never return any attributes, ever.
348:                    pluginClassName = attributes.getValue(pluginClassAttr);
349:                } else {
350:                    pluginClassName = attributes.getValue(pluginClassAttrNs,
351:                            pluginClassAttr);
352:                }
353:
354:                String pluginId;
355:                if (pluginIdAttrNs == null) {
356:                    pluginId = attributes.getValue(pluginIdAttr);
357:                } else {
358:                    pluginId = attributes
359:                            .getValue(pluginIdAttrNs, pluginIdAttr);
360:                }
361:
362:                if (pluginClassName != null) {
363:                    // The user is using a plugin "inline", ie without a previous
364:                    // explicit declaration. If they have used the same plugin class
365:                    // before, we have already gone to the effort of creating a 
366:                    // Declaration object, so retrieve it. If there is no existing
367:                    // declaration object for this class, then create one.
368:
369:                    currDeclaration = pluginManager
370:                            .getDeclarationByClass(pluginClassName);
371:
372:                    if (currDeclaration == null) {
373:                        currDeclaration = new Declaration(pluginClassName);
374:                        try {
375:                            currDeclaration.init(digester, pluginManager);
376:                        } catch (PluginException pwe) {
377:                            throw new PluginInvalidInputException(pwe
378:                                    .getMessage(), pwe.getCause());
379:                        }
380:                        pluginManager.addDeclaration(currDeclaration);
381:                    }
382:                } else if (pluginId != null) {
383:                    currDeclaration = pluginManager
384:                            .getDeclarationById(pluginId);
385:
386:                    if (currDeclaration == null) {
387:                        throw new PluginInvalidInputException("Plugin id ["
388:                                + pluginId + "] is not defined.");
389:                    }
390:                } else if (defaultPlugin != null) {
391:                    currDeclaration = defaultPlugin;
392:                } else {
393:                    throw new PluginInvalidInputException(
394:                            "No plugin class specified for element " + pattern);
395:                }
396:
397:                // get the class of the user plugged-in type
398:                Class pluginClass = currDeclaration.getPluginClass();
399:
400:                String path = digester.getMatch();
401:
402:                // create a new Rules object and effectively push it onto a stack of
403:                // rules objects. The stack is actually a linked list; using the
404:                // PluginRules constructor below causes the new instance to link
405:                // to the previous head-of-stack, then the Digester.setRules() makes
406:                // the new instance the new head-of-stack.
407:                PluginRules newRules = new PluginRules(digester, path,
408:                        oldRules, pluginClass);
409:                digester.setRules(newRules);
410:
411:                if (debug) {
412:                    log.debug("PluginCreateRule.begin: installing new plugin: "
413:                            + "oldrules=" + oldRules.toString() + ", newrules="
414:                            + newRules.toString());
415:                }
416:
417:                // load up the custom rules
418:                currDeclaration.configure(digester, pattern);
419:
420:                // create an instance of the plugin class
421:                Object instance = pluginClass.newInstance();
422:                getDigester().push(instance);
423:                if (debug) {
424:                    log.debug("PluginCreateRule.begin" + ": pattern=["
425:                            + pattern + "]" + " match=[" + digester.getMatch()
426:                            + "]" + " pushed instance of plugin ["
427:                            + pluginClass.getName() + "]");
428:                }
429:
430:                // and now we have to fire any custom rules which would have
431:                // been matched by the same path that matched this rule, had
432:                // they been loaded at that time.
433:                List rules = newRules.getDecoratedRules()
434:                        .match(namespace, path);
435:                fireBeginMethods(rules, namespace, name, attributes);
436:            }
437:
438:            /**
439:             * Process the body text of this element.
440:             *
441:             * @param text The body text of this element
442:             */
443:            public void body(String namespace, String name, String text)
444:                    throws Exception {
445:
446:                // While this class itself has no work to do in the body method,
447:                // we do need to fire the body methods of all dynamically-added
448:                // rules matching the same path as this rule. During begin, we had
449:                // to manually execute the dynamic rules' begin methods because they
450:                // didn't exist in the digester's Rules object when the match begin.
451:                // So in order to ensure consistent ordering of rule execution, the
452:                // PluginRules class deliberately avoids returning any such rules
453:                // in later calls to the match method, instead relying on this
454:                // object to execute them at the appropriate time.
455:                //
456:                // Note that this applies only to rules matching exactly the path
457:                // which is also matched by this PluginCreateRule. 
458:
459:                String path = digester.getMatch();
460:                PluginRules newRules = (PluginRules) digester.getRules();
461:                List rules = newRules.getDecoratedRules()
462:                        .match(namespace, path);
463:                fireBodyMethods(rules, namespace, name, text);
464:            }
465:
466:            /**
467:             * Invoked by the digester when the closing tag matching this Rule's
468:             * pattern is encountered.
469:             * </p>
470:             * 
471:             * @param namespace Description of the Parameter
472:             * @param name Description of the Parameter
473:             * @exception Exception Description of the Exception
474:             *
475:             * @see #begin
476:             */
477:            public void end(String namespace, String name) throws Exception {
478:
479:                // see body method for more info
480:                String path = digester.getMatch();
481:                PluginRules newRules = (PluginRules) digester.getRules();
482:                List rules = newRules.getDecoratedRules()
483:                        .match(namespace, path);
484:                fireEndMethods(rules, namespace, name);
485:
486:                // pop the stack of PluginRules instances, which
487:                // discards all custom rules associated with this plugin
488:                digester.setRules(newRules.getParent());
489:
490:                // and get rid of the instance of the plugin class from the
491:                // digester object stack.
492:                digester.pop();
493:            }
494:
495:            /**
496:             * Return the pattern that this Rule is associated with.
497:             * <p>
498:             * In general, Rule instances <i>can</i> be associated with multiple
499:             * patterns. A PluginCreateRule, however, will only function correctly
500:             * when associated with a single pattern. It is possible to fix this, but
501:             * I can't be bothered just now because this feature is unlikely to be
502:             * used.
503:             * </p>
504:             * 
505:             * @return The pattern value
506:             */
507:            public String getPattern() {
508:                return pattern;
509:            }
510:
511:            /**
512:             * Duplicate the processing that the Digester does when firing the
513:             * begin methods of rules. It would be really nice if the Digester
514:             * class provided a way for this functionality to just be invoked
515:             * directly.
516:             */
517:            public void fireBeginMethods(List rules, String namespace,
518:                    String name, org.xml.sax.Attributes list)
519:                    throws java.lang.Exception {
520:
521:                if ((rules != null) && (rules.size() > 0)) {
522:                    Log log = digester.getLogger();
523:                    boolean debug = log.isDebugEnabled();
524:                    for (int i = 0; i < rules.size(); i++) {
525:                        try {
526:                            Rule rule = (Rule) rules.get(i);
527:                            if (debug) {
528:                                log.debug("  Fire begin() for " + rule);
529:                            }
530:                            rule.begin(namespace, name, list);
531:                        } catch (Exception e) {
532:                            throw digester.createSAXException(e);
533:                        } catch (Error e) {
534:                            throw e;
535:                        }
536:                    }
537:                }
538:            }
539:
540:            /**
541:             * Duplicate the processing that the Digester does when firing the
542:             * body methods of rules. It would be really nice if the Digester
543:             * class provided a way for this functionality to just be invoked
544:             * directly.
545:             */
546:            private void fireBodyMethods(List rules, String namespaceURI,
547:                    String name, String text) throws Exception {
548:
549:                if ((rules != null) && (rules.size() > 0)) {
550:                    Log log = digester.getLogger();
551:                    boolean debug = log.isDebugEnabled();
552:                    for (int i = 0; i < rules.size(); i++) {
553:                        try {
554:                            Rule rule = (Rule) rules.get(i);
555:                            if (debug) {
556:                                log.debug("  Fire body() for " + rule);
557:                            }
558:                            rule.body(namespaceURI, name, text);
559:                        } catch (Exception e) {
560:                            throw digester.createSAXException(e);
561:                        } catch (Error e) {
562:                            throw e;
563:                        }
564:                    }
565:                }
566:            }
567:
568:            /**
569:             * Duplicate the processing that the Digester does when firing the
570:             * end methods of rules. It would be really nice if the Digester
571:             * class provided a way for this functionality to just be invoked
572:             * directly.
573:             */
574:            public void fireEndMethods(List rules, String namespaceURI,
575:                    String name) throws Exception {
576:
577:                // Fire "end" events for all relevant rules in reverse order
578:                if (rules != null) {
579:                    Log log = digester.getLogger();
580:                    boolean debug = log.isDebugEnabled();
581:                    for (int i = 0; i < rules.size(); i++) {
582:                        int j = (rules.size() - i) - 1;
583:                        try {
584:                            Rule rule = (Rule) rules.get(j);
585:                            if (debug) {
586:                                log.debug("  Fire end() for " + rule);
587:                            }
588:                            rule.end(namespaceURI, name);
589:                        } catch (Exception e) {
590:                            throw digester.createSAXException(e);
591:                        } catch (Error e) {
592:                            throw e;
593:                        }
594:                    }
595:                }
596:            }
597:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.