Source Code Cross Referenced for ClassTree.java in  » Development » javaguard » net » sf » javaguard » 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 » Development » javaguard » net.sf.javaguard 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


0001:        /**
0002:         * JavaGuard -- an obfuscation package for Java classfiles.
0003:         *
0004:         * Copyright (c) 1999 Mark Welsh (markw@retrologic.com)
0005:         * Copyright (c) 2002 Thorsten Heit (theit@gmx.de)
0006:         *
0007:         * This library is free software; you can redistribute it and/or
0008:         * modify it under the terms of the GNU Lesser General Public
0009:         * License as published by the Free Software Foundation; either
0010:         * version 2 of the License, or (at your option) any later version.
0011:         *
0012:         * This library is distributed in the hope that it will be useful,
0013:         * but WITHOUT ANY WARRANTY; without even the implied warranty of
0014:         * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
0015:         * Lesser General Public License for more details.
0016:         *
0017:         * You should have received a copy of the GNU Lesser General Public
0018:         * License along with this library; if not, write to the Free Software
0019:         * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
0020:         *
0021:         * The author may be contacted at theit@gmx.de.
0022:         *
0023:         *
0024:         * $Id: ClassTree.java,v 1.20 2002/05/28 17:26:45 glurk Exp $
0025:         */package net.sf.javaguard;
0026:
0027:        import java.io.*;
0028:        import java.lang.reflect.*;
0029:        import java.util.*;
0030:        import net.sf.javaguard.classfile.*;
0031:        import net.sf.javaguard.log.*;
0032:
0033:        import org.apache.oro.text.regex.*;
0034:
0035:        /** Tree structure of package levels, classes, methods and fields used for
0036:         * obfuscation.
0037:         *
0038:         * @author <a href="mailto:markw@retrologic.com">Mark Welsh</a>
0039:         * @author <a href="mailto:theit@gmx.de">Thorsten Heit</a>
0040:         */
0041:        public class ClassTree implements  NameMapper {
0042:            /** Package separator character. */
0043:            public static final char PACKAGE_LEVEL = '/';
0044:            /** Inner class separator character. */
0045:            public static final char CLASS_LEVEL = '$';
0046:            /** Method and field separator character. */
0047:            public static final char METHOD_FIELD_LEVEL = '/';
0048:
0049:            /** Holds the class path of the java.io.Serializable interface. */
0050:            public static final String SERIALIZABLE_INTERFACE = "java/io/Serializable";
0051:            /** Holds the class path of the java.io.Serializable interface. */
0052:            public static final String SERIALIZABLE_INTERFACE_CLASS = "java.io.Serializable";
0053:
0054:            /** Holds the class path of the java.rmi.Remote interface. */
0055:            public static final String REMOTE_INTERFACE = "java/rmi/Remote";
0056:            /** Holds the class path ofthe java.rmi.Remote interface. */
0057:            public static final String REMOTE_INTERFACE_CLASS = "java.rmi.Remote";
0058:            /** Holds the class path of the java.rmi.server.Skeleton interface. */
0059:            public static final String SKELETON_INTERFACE = "java/rmi/server/Skeleton";
0060:            /** Holds the class path of the java.rmi.server.Skeleton interface. */
0061:            public static final String SKELETON_INTERFACE_CLASS = "java.rmi.server.Skeleton";
0062:
0063:            /** Holds the class name suffix for stub classes generated by rmic. */
0064:            private static final String STR_STUB = "_Stub";
0065:            /** Holds the class name suffix for skeleton classes generated by rmic. */
0066:            private static final String STR_SKEL = "_Skel";
0067:
0068:            /** Stores tree items of serializable field items that may not be obfuscated. */
0069:            private Vector serializableFields;
0070:            /** Stores pairs (fully-qualified name, descriptor) of methods that may
0071:             * not be obfuscated. */
0072:            private Vector serializableMethods;
0073:            /** Stores classes that implement the Remote or Skeleton interface. */
0074:            private Vector remoteClasses;
0075:
0076:            /** Holds classes that are used in hardcoded references. */
0077:            private Set hardcodedReferences;
0078:
0079:            /** Holds the compiler for regular expressions. */
0080:            private PatternCompiler patternCompiler;
0081:            /** Holds the regular expression matcher class. */
0082:            private PatternMatcher patternMatcher;
0083:
0084:            /** Holds a map of compiled default regular expressions. */
0085:            private Map patternsIgnoreDefault;
0086:            /** Holds a map of compiled regular expressions for package names. */
0087:            private Map patternsIgnorePackage;
0088:            /** Holds a map of compiled regular expressions for class names. */
0089:            private Map patternsIgnoreClass;
0090:            /** Holds a map of compiled regular expressions for method names. */
0091:            private Map patternsIgnoreMethod;
0092:            /** Holds a map of compiled regular expressions for field names. */
0093:            private Map patternsIgnoreField;
0094:
0095:            /** Holds a map of compiled default regular expressions. */
0096:            private Map patternsObfuscateDefault;
0097:            /** Holds a map of compiled regular expressions for package names. */
0098:            private Map patternsObfuscatePackage;
0099:            /** Holds a map of compiled regular expressions for class names. */
0100:            private Map patternsObfuscateClass;
0101:            /** Holds a map of compiled regular expressions for method names. */
0102:            private Map patternsObfuscateMethod;
0103:            /** Holds a map of compiled regular expressions for field names. */
0104:            private Map patternsObfuscateField;
0105:
0106:            /** Holds a list of attributes to retain. */
0107:            private Vector retainAttrs = new Vector();
0108:            /** Holds the root package in the database (Java default package). */
0109:            private Pk root;
0110:
0111:            /** Hold whether the obfuscator should respect remote classes. */
0112:            private static boolean useRmicClasses = false;
0113:            /** Holds whether resource file names should be obfuscated according to
0114:             * their corresponding class files. */
0115:            private static boolean obfuscateResources = false;
0116:            /** Holds whether we should automatically prevent hardcoded class names from
0117:             * being obfuscated. */
0118:            private static boolean autoCorrectClassNames = false;
0119:
0120:            /** Holds the log file. */
0121:            private FileLogger logfile;
0122:            /** Holds the logger. */
0123:            private ScreenLogger logger;
0124:
0125:            /** Constructor that initializes the class tree.
0126:             */
0127:            public ClassTree() {
0128:                setRootPackage(Pk.createRoot(this ));
0129:
0130:                serializableFields = new Vector();
0131:                serializableMethods = new Vector();
0132:                remoteClasses = new Vector();
0133:
0134:                hardcodedReferences = new TreeSet();
0135:
0136:                patternCompiler = new Perl5Compiler();
0137:                patternMatcher = new Perl5Matcher();
0138:
0139:                // Initialize the maps that store the ignore directives taken from the
0140:                // script file
0141:                patternsIgnoreDefault = new HashMap();
0142:                patternsIgnorePackage = new HashMap();
0143:                patternsIgnoreClass = new HashMap();
0144:                patternsIgnoreMethod = new HashMap();
0145:                patternsIgnoreField = new HashMap();
0146:
0147:                // Initialize the maps that store the obfuscate directives taken from the
0148:                // script file
0149:                patternsObfuscateDefault = new HashMap();
0150:                patternsObfuscatePackage = new HashMap();
0151:                patternsObfuscateClass = new HashMap();
0152:                patternsObfuscateMethod = new HashMap();
0153:                patternsObfuscateField = new HashMap();
0154:
0155:                logfile = FileLogger.getInstance();
0156:                logger = ScreenLogger.getInstance();
0157:            }
0158:
0159:            /** Sets the root package level.
0160:             * @param pk the root package
0161:             * @see #getRootPackage
0162:             */
0163:            protected void setRootPackage(Pk pk) {
0164:                root = pk;
0165:            }
0166:
0167:            /** Returns the root package.
0168:             * @return root package
0169:             * @see #setRootPackage
0170:             */
0171:            public Pk getRootPackage() {
0172:                return root;
0173:            }
0174:
0175:            /** Defines whether or not the obfuscator should respect the names of stub
0176:             * and skeleton classes generated by rmic.
0177:             * @param canUse a string holding "true", "yes" or "on" if the obfuscator
0178:             * should respect the names
0179:             * @see #setUseRmicClasses(boolean)
0180:             */
0181:            public void setUseRmicClasses(String canUse) {
0182:                setUseRmicClasses(parseBooleanValue(canUse));
0183:            }
0184:
0185:            /** Defines whether or not the obfuscator should respect the names of stub
0186:             * and skeleton classes generated by rmic.
0187:             * @param canUse true if the obfuscator should respect class names; false else
0188:             * false else
0189:             * @see #canUseRmicClasses
0190:             */
0191:            public void setUseRmicClasses(boolean canUse) {
0192:                useRmicClasses = canUse;
0193:            }
0194:
0195:            /** Returns true if the obfuscator should respect stub and skeleton class
0196:             * names.
0197:             * @return true if the obfuscator should respect stub and skeleton class
0198:             * names; false else
0199:             * @see #setUseRmicClasses(boolean)
0200:             */
0201:            public boolean canUseRmicClasses() {
0202:                return useRmicClasses;
0203:            }
0204:
0205:            /** Defines whether resource file names should be obfuscated according to
0206:             * their corresponding class files or not.
0207:             * @param obfuscate a string holding "true", "yes" or "on" if the obfuscator
0208:             * rename resource files
0209:             * @see #setObfuscateResources(boolean)
0210:             */
0211:            public void setObfuscateResources(String obfuscate) {
0212:                setObfuscateResources(parseBooleanValue(obfuscate));
0213:            }
0214:
0215:            /** Defines whether resource file names should be obfuscated according to
0216:             * their corresponding class files or not.
0217:             * @param obfuscate true if resource file names should be obfuscated; false
0218:             * else
0219:             * @see #canObfuscateResources
0220:             */
0221:            public void setObfuscateResources(boolean obfuscate) {
0222:                obfuscateResources = obfuscate;
0223:            }
0224:
0225:            /** Returns whether resource file names should be obfuscated according to
0226:             * their corresponding class files or not.
0227:             * @return true if resource file names should be obfuscated; false else
0228:             * @see #setObfuscateResources(boolean)
0229:             */
0230:            public boolean canObfuscateResources() {
0231:                return obfuscateResources;
0232:            }
0233:
0234:            /** Defines whether we should automatically prevent hardcoded class names from
0235:             * being obfuscated.
0236:             * @param autoCorrect a string holding "true", "yes" or "on" if the obfuscator
0237:             * should prevent hardcoded class names from being obfuscated
0238:             * @see #setAutoCorrectClassNames(boolean)
0239:             */
0240:            public void setAutoCorrectClassNames(String autoCorrect) {
0241:                setAutoCorrectClassNames(parseBooleanValue(autoCorrect));
0242:            }
0243:
0244:            /** Defines whether we should automatically prevent hardcoded class names from
0245:             * being obfuscated.
0246:             * @param autoCorrect true if hardcoded class names should not be obfuscated;
0247:             * false else
0248:             * @see #canAutoCorrectClassNames
0249:             */
0250:            public void setAutoCorrectClassNames(boolean autoCorrect) {
0251:                autoCorrectClassNames = autoCorrect;
0252:            }
0253:
0254:            /** Returns whether we prevent hardcoded class names from being obfuscated.
0255:             * @return true if hardcoded class names should not be obfuscated; false else
0256:             * @see #setAutoCorrectClassNames
0257:             */
0258:            public boolean canAutoCorrectClassNames() {
0259:                return autoCorrectClassNames;
0260:            }
0261:
0262:            /** Parses the string and creates a boolean value from it.
0263:             * @param str the string to parse
0264:             * @return true if the string is "true", "yes" or "on"; false else
0265:             */
0266:            private boolean parseBooleanValue(String str) {
0267:                if (str.equalsIgnoreCase("true") || str.equalsIgnoreCase("yes")
0268:                        || str.equalsIgnoreCase("on")) {
0269:                    return true;
0270:                }
0271:                return false;
0272:            }
0273:
0274:            /** Splits a fully qualified name into package and class name segments.
0275:             * @param name fully qualified name
0276:             * @return iterator that contains package/class name segments.
0277:             * @throws IllegalStateException if the name is invalid
0278:             */
0279:            private Iterator splitName(String name)
0280:                    throws IllegalStateException {
0281:                Vector vec = new Vector();
0282:                String nameOrig = name;
0283:                while (!name.equals("")) {
0284:                    int posP = name.indexOf(PACKAGE_LEVEL);
0285:                    int posC = name.indexOf(CLASS_LEVEL);
0286:                    KeyValue kv = null;
0287:                    // the current string only consists of a class name
0288:                    if (posP == -1 && posC == -1) {
0289:                        kv = new KeyValue(new Character(CLASS_LEVEL), name);
0290:                        name = "";
0291:                    }
0292:                    // the current string only consists of a class and a subclass name
0293:                    if (posP == -1 && posC != -1) {
0294:                        kv = new KeyValue(new Character(CLASS_LEVEL), name
0295:                                .substring(0, posC));
0296:                        name = name.substring(posC + 1, name.length());
0297:                    }
0298:                    // the current string contains a package name, but no subclass name
0299:                    if (posP != -1 && posC == -1) {
0300:                        kv = new KeyValue(new Character(PACKAGE_LEVEL), name
0301:                                .substring(0, posP));
0302:                        name = name.substring(posP + 1, name.length());
0303:                    }
0304:                    // the current string contains of both a package and a subclass name
0305:                    if (posP != -1 && posC != -1) {
0306:                        if (posP < posC) {
0307:                            kv = new KeyValue(new Character(PACKAGE_LEVEL),
0308:                                    name.substring(0, posP));
0309:                            name = name.substring(posP + 1, name.length());
0310:                        } else {
0311:                            throw new IllegalStateException(
0312:                                    "Invalid fully qualified name (a): "
0313:                                            + nameOrig);
0314:                        }
0315:                    }
0316:                    if (((String) kv.getValue()).equals("")) {
0317:                        throw new IllegalStateException(
0318:                                "Invalid fully qualified name (b): " + nameOrig);
0319:                    }
0320:                    vec.addElement(kv);
0321:                }
0322:                return vec.iterator();
0323:            }
0324:
0325:            /** Update the path of the given filename. All package and (inner) class
0326:             * names are replaced by their obfuscated output names. If the input name
0327:             * specifies a resource file its output name can also be obfuscated if the
0328:             * corresponding class is found in the class tree.
0329:             * @param inName the file name to update
0330:             * @return updated output file name
0331:             */
0332:            public String getOutputFileName(String inName) {
0333:                boolean isClass = false;
0334:                // if the file name denotes a class remove the ".class" extension
0335:                if (inName.endsWith(ClassConstants.CLASS_EXT)) {
0336:                    isClass = true;
0337:                    inName = inName.substring(0, inName
0338:                            .lastIndexOf(ClassConstants.CLASS_EXT));
0339:                }
0340:
0341:                TreeItem ti = getRootPackage();
0342:                StringBuffer sb = new StringBuffer();
0343:                Iterator iter = splitName(inName);
0344:                while (iter.hasNext()) {
0345:                    KeyValue nameSegment = (KeyValue) iter.next();
0346:                    char tag = ((Character) nameSegment.getKey()).charValue();
0347:                    String name = (String) nameSegment.getValue();
0348:                    switch (tag) {
0349:                    case PACKAGE_LEVEL:
0350:                        // try to search the child list of the current tree item for a
0351:                        // subpackage named <name>
0352:                        if (null != ti) {
0353:                            // find the named package in the current tree item
0354:                            ti = ((Pk) ti).getPackage(name);
0355:                            if (null != ti) {
0356:                                // tree item found -> append its (obfuscated) output name
0357:                                sb.append(ti.getOutName());
0358:                            } else {
0359:                                // tree item not found -> use the original name
0360:                                sb.append(name);
0361:                            }
0362:                        } else {
0363:                            // we don't have a tree item -> use the original name
0364:                            sb.append(name);
0365:                        }
0366:                        sb.append(PACKAGE_LEVEL);
0367:                        break;
0368:
0369:                    case CLASS_LEVEL:
0370:                        // check whether the current name belongs to a (inner) class name
0371:                        if (isClass
0372:                                || (iter.hasNext() && canObfuscateResources())) {
0373:                            // current name belongs to an inner class
0374:                            ti = ((PkCl) ti).getClass(name);
0375:                            if (null != ti) {
0376:                                // tree item found -> append its (obfuscated) output name
0377:                                sb.append(ti.getOutName());
0378:                            } else {
0379:                                // tree item not found -> use the original name
0380:                                sb.append(name);
0381:                            }
0382:                            // if there's at least one more inner class add the inner class
0383:                            // separator character
0384:                            if (iter.hasNext()) {
0385:                                sb.append(CLASS_LEVEL);
0386:                            }
0387:                        } else {
0388:                            // the remaining name belongs to a resource file
0389:                            if (!canObfuscateResources()) {
0390:                                sb.append(name);
0391:                                if (iter.hasNext()) {
0392:                                    sb.append(CLASS_LEVEL);
0393:                                }
0394:                            } else {
0395:                                // find the (localized) class whose name equals the actual name
0396:                                ti = findInnerClass((PkCl) ti, name);
0397:                                if (null == ti) {
0398:                                    sb.append(name);
0399:                                } else {
0400:                                    // the returned tree item has the same input name as the actual
0401:                                    // name (apart from a localized ending such as _de_DE)
0402:                                    String suffix = name.substring(ti
0403:                                            .getInName().length());
0404:                                    sb.append(ti.getOutName());
0405:                                    sb.append(suffix);
0406:                                }
0407:                            }
0408:                        }
0409:                        break;
0410:
0411:                    default:
0412:                        throw new InternalError(
0413:                                "Internal error: illegal package/class name tag");
0414:                    }
0415:                }
0416:                return sb.toString();
0417:            }
0418:
0419:            /** Tries find the inner class whose name equals the (localized) given
0420:             * resource name.
0421:             * @param pkcl the class to search; may be null
0422:             * @param name the name of a resource file; may be null
0423:             * @return the inner class whose name matches the given resource file name;
0424:             * null if no class class is found or one of the input parameters is null
0425:             */
0426:            private Cl findInnerClass(PkCl pkcl, String name) {
0427:                if (null == pkcl || null == name)
0428:                    return null;
0429:
0430:                // the remaining name belongs to a resource file
0431:                String prefix = null;
0432:                String suffix = null;
0433:                int pos = name.lastIndexOf('.');
0434:                // extract the file name prefix and suffix
0435:                if (pos > 0) {
0436:                    prefix = name.substring(0, pos);
0437:                    suffix = name.substring(pos + 1);
0438:                } else if (0 == pos) {
0439:                    // extract the suffix only if the file name is not "."
0440:                    suffix = name.substring(pos + 1);
0441:                } else {
0442:                    // we don't have a suffix -> name = prefix
0443:                    prefix = name;
0444:                }
0445:
0446:                // try to find the class that corresponds to the actual name
0447:                try {
0448:                    while (null != prefix) {
0449:                        Cl cl = pkcl.getClass(prefix);
0450:                        if (null != cl) {
0451:                            return cl;
0452:                        }
0453:                        prefix = prefix.substring(0, prefix.lastIndexOf('_'));
0454:                    }
0455:                } catch (IndexOutOfBoundsException e) {
0456:                    // exception only occurs if the remaining prefix isn't localized anymore
0457:                }
0458:
0459:                // if the given resource file name doesn't have a prefix return null
0460:                return null;
0461:            }
0462:
0463:            /** Add a classfile's package, class, method and field entries to the internal
0464:             * database.
0465:             * @param cf the class file to add
0466:             */
0467:            public void addClassFile(ClassFile cf) {
0468:                // Add the fully qualified class name
0469:                TreeItem ti = getRootPackage();
0470:                char parentTag = PACKAGE_LEVEL;
0471:                for (Iterator iter = splitName(cf.getName()); iter.hasNext();) {
0472:                    KeyValue nameSegment = (KeyValue) iter.next();
0473:                    char tag = ((Character) nameSegment.getKey()).charValue();
0474:                    String name = (String) nameSegment.getValue();
0475:                    switch (tag) {
0476:                    case PACKAGE_LEVEL:
0477:                        // insert a new subpackage with the current name if it doesn't exist
0478:                        ti = ((Pk) ti).addPackage(name);
0479:                        break;
0480:
0481:                    case CLASS_LEVEL:
0482:                        // If this is an inner class, just add placeholder classes up the tree
0483:                        if (iter.hasNext()) {
0484:                            ti = ((PkCl) ti).addPlaceholderClass(name);
0485:                        } else {
0486:                            ti = ((PkCl) ti).addClass(name, cf.getSuper(), cf
0487:                                    .getInterfaceNames());
0488:                        }
0489:                        break;
0490:
0491:                    default:
0492:                        throw new InternalError(
0493:                                "Internal error: illegal package/class name tag");
0494:                    }
0495:                    parentTag = tag;
0496:                }
0497:
0498:                // We must have a class before adding methods and fields
0499:                if (ti instanceof  Cl) {
0500:                    Cl cl = (Cl) ti;
0501:
0502:                    // Add the class's methods to the database
0503:                    for (int i = 0; i < cf.getMethodsCount(); i++) {
0504:                        MethodInfo mi = cf.getMethodInfo(i);
0505:                        cl.addMethod(mi.isSynthetic(), mi.getName(), mi
0506:                                .getDescriptor(), mi.getAccessFlags());
0507:                    }
0508:
0509:                    // Add the class's fields to the database
0510:                    for (int i = 0; i < cf.getFieldsCount(); i++) {
0511:                        FieldInfo fi = cf.getFieldInfo(i);
0512:                        cl.addField(fi.isSynthetic(), fi.getName(), fi
0513:                                .getDescriptor(), fi.getAccessFlags());
0514:                    }
0515:                } else {
0516:                    throw new InternalError(
0517:                            "Internal error: invalid class file!");
0518:                }
0519:
0520:                // add the class names that are used in hardcoded references to the internal
0521:                // list so we can process them later
0522:                hardcodedReferences.addAll(cf.getHardcodedClassNames());
0523:            }
0524:
0525:            /** Mark an attribute type for retention.
0526:             * @param entry the script file attribute entry to retain
0527:             * @see #setUseRmicClasses(String)
0528:             * @see #setUseRmicClasses(boolean)
0529:             * @see #setAutoCorrectClassNames(String)
0530:             * @see #setAutoCorrectClassNames(boolean)
0531:             * @see #setObfuscateResources(String)
0532:             * @see #setObfuscateResources(boolean)
0533:             */
0534:            public void retainAttribute(ScriptEntry entry) {
0535:                logger.println("retaining attribute " + entry.getName());
0536:
0537:                if (entry.getName().equals(ScriptConstants.RENAME_RMIC)) {
0538:                    // turn on/off special processing for RMIC-generated classes
0539:                    if (null != entry.getInfo()) {
0540:                        logger.log(Log.VERBOSE, "-> getInfo(): "
0541:                                + entry.getInfo());
0542:                        setUseRmicClasses(entry.getInfo());
0543:                    } else {
0544:                        setUseRmicClasses(true);
0545:                    }
0546:                } else if (entry.getName().equals(
0547:                        ScriptConstants.PRESERVE_REFERENCES)) {
0548:                    // turn on/off autocorrection of classes used in hardcoded references
0549:                    if (null != entry.getInfo()) {
0550:                        logger.log(Log.VERBOSE, "-> getInfo(): "
0551:                                + entry.getInfo());
0552:                        setAutoCorrectClassNames(entry.getInfo());
0553:                    } else {
0554:                        setAutoCorrectClassNames(true);
0555:                    }
0556:                } else if (entry.getName().equals(
0557:                        ScriptConstants.RENAME_RESOURCES)) {
0558:                    // turn on/off renaming of resource files
0559:                    if (null != entry.getInfo()) {
0560:                        logger.log(Log.VERBOSE, "-> getInfo(): "
0561:                                + entry.getInfo());
0562:                        setObfuscateResources(entry.getInfo());
0563:                    } else {
0564:                        setObfuscateResources(true);
0565:                    }
0566:                } else {
0567:                    retainAttrs.addElement(entry.getName());
0568:                }
0569:            }
0570:
0571:            /** Marks an item in the tree for retention.
0572:             * @param ti the tree item
0573:             */
0574:            private void retainItem(TreeItem ti) {
0575:                ti.setOutName(ti.getInName());
0576:                ti.setFromScript();
0577:            }
0578:
0579:            /** Marks a list of items in the tree for retention.
0580:             * @param iter an iterator for the items to retain
0581:             * @ee #retainItem
0582:             */
0583:            private void retainItems(Iterator iter) {
0584:                while (iter.hasNext()) {
0585:                    retainItem((TreeItem) iter.next());
0586:                }
0587:            }
0588:
0589:            /** Mark an item for retention, and specify its new name.
0590:             * @param ti the tree item
0591:             * @param obfName the obfuscated name of the item
0592:             */
0593:            private void retainItemMap(TreeItem ti, String obfName) {
0594:                ti.setOutName(obfName);
0595:                ti.setFromScriptMap();
0596:            }
0597:
0598:            /** Mark a tree item and all its parents for retention.
0599:             * @param ti the tree item
0600:             */
0601:            private void retainHierarchy(TreeItem ti) {
0602:                if (null != ti) {
0603:                    retainItem(ti);
0604:                    retainHierarchy(ti.getParent());
0605:                }
0606:            }
0607:
0608:            /** Traverse the class tree and generate obfuscated names within each
0609:             * namespace.
0610:             */
0611:            public void generateNames() {
0612:                logger.log(Log.VERBOSE, "Generate obfuscated names");
0613:                walkTree(new TreeAction() {
0614:                    public void packageAction(Pk pk) {
0615:                        pk.generateNames();
0616:                    }
0617:
0618:                    public void classAction(Cl cl) {
0619:                        cl.generateNames();
0620:                    }
0621:
0622:                    public void methodAction(Md md) {
0623:                    }
0624:
0625:                    public void fieldAction(Fd fd) {
0626:                    }
0627:                });
0628:            }
0629:
0630:            /** Resolve the polymorphic dependencies of each class.
0631:             */
0632:            public void resolveClasses() {
0633:                logger.log(Log.VERBOSE, "Resolve polymorphic dependencies...");
0634:                walkTree(new TreeAction() {
0635:                    public void classAction(Cl cl) {
0636:                        cl.resetResolve();
0637:                    }
0638:
0639:                    public void packageAction(Pk pk) {
0640:                    }
0641:
0642:                    public void methodAction(Md md) {
0643:                    }
0644:
0645:                    public void fieldAction(Fd fd) {
0646:                    }
0647:                });
0648:
0649:                walkTree(new TreeAction() {
0650:                    public void classAction(Cl cl) {
0651:                        cl.setupNameListDowns();
0652:                    }
0653:
0654:                    public void packageAction(Pk pk) {
0655:                    }
0656:
0657:                    public void methodAction(Md md) {
0658:                    }
0659:
0660:                    public void fieldAction(Fd fd) {
0661:                    }
0662:                });
0663:
0664:                Cl.nameSpace = 0;
0665:                walkTree(new TreeAction() {
0666:                    public void classAction(Cl cl) {
0667:                        cl.resolveOptimally();
0668:                    }
0669:
0670:                    public void packageAction(Pk pk) {
0671:                    }
0672:
0673:                    public void methodAction(Md md) {
0674:                    }
0675:
0676:                    public void fieldAction(Fd fd) {
0677:                    }
0678:                });
0679:            }
0680:
0681:            /** Return a list of attributes marked to keep.
0682:             * @return array with attributes to keep
0683:             */
0684:            public String[] getAttrsToKeep() {
0685:                String[] attrs = new String[retainAttrs.size()];
0686:                for (int i = 0; i < attrs.length; i++) {
0687:                    attrs[i] = (String) retainAttrs.elementAt(i);
0688:                }
0689:                return attrs;
0690:            }
0691:
0692:            /** Find all packages in the tree that match a given pattern.
0693:             * @param pattern a regular expression containing the search pattern
0694:             * @return an iterator for all packages that match the search pattern
0695:             */
0696:            public Iterator findPackages(final Pattern pattern) {
0697:                final Vector vec = new Vector();
0698:                walkTree(new TreeAction() {
0699:                    public void packageAction(Pk pk) {
0700:                        if (patternMatcher
0701:                                .contains(pk.getFullInName(), pattern)
0702:                                || patternMatcher.contains(pk.getInName(),
0703:                                        pattern)) {
0704:                            vec.addElement(pk);
0705:                        }
0706:                    }
0707:
0708:                    public void classAction(Cl cl) {
0709:                    }
0710:
0711:                    public void methodAction(Md md) {
0712:                    }
0713:
0714:                    public void fieldAction(Fd fd) {
0715:                    }
0716:                });
0717:                if (vec.isEmpty()) {
0718:                    logger.log("Warning: No package found for search pattern '"
0719:                            + pattern.getPattern() + "'");
0720:                }
0721:                return vec.iterator();
0722:            }
0723:
0724:            /** Find all classes in the tree that match a given pattern.
0725:             * @param pattern a regular expression containing the search pattern
0726:             * @return an iterator for all classes that match the search pattern
0727:             */
0728:            public Iterator findClasses(final Pattern pattern) {
0729:                final Vector vec = new Vector();
0730:                walkTree(new TreeAction() {
0731:                    public void classAction(Cl cl) {
0732:                        if (patternMatcher
0733:                                .contains(cl.getFullInName(), pattern)
0734:                                || patternMatcher.contains(cl.getInName(),
0735:                                        pattern)) {
0736:                            vec.addElement(cl);
0737:                        }
0738:                    }
0739:
0740:                    public void packageAction(Pk pk) {
0741:                    }
0742:
0743:                    public void methodAction(Md md) {
0744:                    }
0745:
0746:                    public void fieldAction(Fd fd) {
0747:                    }
0748:                });
0749:                if (vec.isEmpty()) {
0750:                    logger.log("Warning: No class found for search pattern '"
0751:                            + pattern.getPattern() + "'");
0752:                }
0753:                return vec.iterator();
0754:            }
0755:
0756:            /** Find all methods in the tree that match a given pattern.
0757:             * @param pattern a regular expression containing the search pattern
0758:             * @param descr an optional descriptor; may be null
0759:             * @return an iterator for all methods that match the search pattern
0760:             */
0761:            public Iterator findMethods(final Pattern pattern,
0762:                    final String descr) {
0763:                final Vector vec = new Vector();
0764:                walkTree(new TreeAction() {
0765:                    public void methodAction(Md md) {
0766:                        if (patternMatcher
0767:                                .contains(md.getFullInName(), pattern)
0768:                                || patternMatcher.contains(md.getInName(),
0769:                                        pattern)) {
0770:                            if (null == descr
0771:                                    || descr.equals(md.getDescriptor())) {
0772:                                vec.addElement(md);
0773:                            }
0774:                        }
0775:                    }
0776:
0777:                    public void packageAction(Pk pk) {
0778:                    }
0779:
0780:                    public void classAction(Cl cl) {
0781:                    }
0782:
0783:                    public void fieldAction(Fd fd) {
0784:                    }
0785:                });
0786:                if (vec.isEmpty()) {
0787:                    logger.log("Warning: No method found for search pattern '"
0788:                            + pattern.getPattern() + "'");
0789:                }
0790:                return vec.iterator();
0791:            }
0792:
0793:            /** Find all methods in the tree that match a given pattern.
0794:             * @param pattern a regular expression containing the search pattern
0795:             * @param descr an optional descriptor; may be null
0796:             * @return an iterator for all methods that match the search pattern
0797:             */
0798:            public Iterator findFields(final Pattern pattern, final String descr) {
0799:                final Vector vec = new Vector();
0800:                walkTree(new TreeAction() {
0801:                    public void fieldAction(Fd fd) {
0802:                        if (patternMatcher
0803:                                .contains(fd.getFullInName(), pattern)
0804:                                || patternMatcher.contains(fd.getInName(),
0805:                                        pattern)) {
0806:                            if (null == descr
0807:                                    || descr.equals(fd.getDescriptor())) {
0808:                                vec.addElement(fd);
0809:                            }
0810:                        }
0811:                    }
0812:
0813:                    public void packageAction(Pk pk) {
0814:                    }
0815:
0816:                    public void classAction(Cl cl) {
0817:                    }
0818:
0819:                    public void methodAction(Md md) {
0820:                    }
0821:                });
0822:                if (vec.isEmpty()) {
0823:                    logger.log("Warning: No field found for search pattern '"
0824:                            + pattern.getPattern() + "'");
0825:                }
0826:                return vec.iterator();
0827:            }
0828:
0829:            /** Get a class in the tree from the fully qualified name, returning null if
0830:             * the name is not found.
0831:             * @param fullName fully qualified class name
0832:             * @return class stored in the tree; null if the name is not found.
0833:             * @throws IllegalStateException if an error exists inside the tree
0834:             */
0835:            public Cl getCl(String fullName) throws IllegalStateException {
0836:                TreeItem ti = getRootPackage();
0837:                for (Iterator iter = splitName(fullName); iter.hasNext();) {
0838:                    KeyValue nameSegment = (KeyValue) iter.next();
0839:                    char tag = ((Character) nameSegment.getKey()).charValue();
0840:                    String name = (String) nameSegment.getValue();
0841:                    switch (tag) {
0842:                    case PACKAGE_LEVEL:
0843:                        ti = ((Pk) ti).getPackage(name);
0844:                        break;
0845:
0846:                    case CLASS_LEVEL:
0847:                        ti = ((PkCl) ti).getClass(name);
0848:                        break;
0849:
0850:                    default:
0851:                        throw new IllegalStateException(
0852:                                "Internal error: illegal package/class name tag");
0853:                    }
0854:
0855:                    // If the name is not in the database, return null
0856:                    if (ti == null) {
0857:                        return null;
0858:                    }
0859:                }
0860:
0861:                // It is an error if we do not end up with a class or interface
0862:                if (!(ti instanceof  Cl)) {
0863:                    throw new IllegalStateException(
0864:                            "Inconsistent class or interface name.");
0865:                }
0866:                return (Cl) ti;
0867:            }
0868:
0869:            /** Find a class in the tree from the fully qualified name. If the class isn't
0870:             * found directly try to check whether it is an inner class.
0871:             * the name is not found.
0872:             * @param fullName fully qualified class name
0873:             * @return class stored in the tree; null if the name is not found.
0874:             * @throws IllegalStateException if an error exists inside the tree
0875:             * @see #getCl
0876:             */
0877:            public Cl findClass(String fullName) throws IllegalStateException {
0878:                // first replace all '.' separator characters by the one used in the
0879:                // internal representation
0880:                fullName = fullName.replace('.', ClassFile.SEP_REGULAR
0881:                        .charAt(0));
0882:                Cl cl = getCl(fullName);
0883:                // if we cannot find the item check whether it's an inner class
0884:                if (null == cl) {
0885:                    int pos;
0886:                    String str = fullName;
0887:                    while (null == cl
0888:                            && (pos = str.lastIndexOf(ClassFile.SEP_REGULAR)) >= 0) {
0889:                        str = str.substring(0, pos) + ClassFile.SEP_INNER
0890:                                + str.substring(pos + 1);
0891:                        cl = getCl(str);
0892:                    }
0893:                }
0894:                return cl;
0895:            }
0896:
0897:            /** Get a package in tree from the fully qualified name.
0898:             * @param fullName the fully qualified name of the package
0899:             * @return package in the tree; null if name not found.
0900:             * @throws IllegalStateException if an error exists inside the tree
0901:             */
0902:            public Pk getPk(String fullName) throws IllegalStateException {
0903:                TreeItem ti = getRootPackage();
0904:                for (Iterator iter = splitName(fullName); iter.hasNext();) {
0905:                    KeyValue nameSegment = (KeyValue) iter.next();
0906:                    String name = (String) nameSegment.getValue();
0907:                    ti = ((Pk) ti).getPackage(name);
0908:
0909:                    // If the name is not in the database, return null
0910:                    if (ti == null) {
0911:                        return null;
0912:                    }
0913:                    // It is an error if we do not end up with a package
0914:                    if (!(ti instanceof  Pk)) {
0915:                        throw new IllegalStateException("Inconsistent package.");
0916:                    }
0917:                }
0918:                return (Pk) ti;
0919:            }
0920:
0921:            /** Get method in tree from the fully qualified name.
0922:             * @param fullName the fully qualified method name
0923:             * @param descriptor an optional descriptor for the method
0924:             * @return method item in the tree; null if the element is not found
0925:             * @throws IllegalStateException if an error exists inside the tree
0926:             */
0927:            public Md getMd(String fullName, String descriptor)
0928:                    throws IllegalStateException {
0929:                // Split into class and method names
0930:                int pos = fullName.lastIndexOf(METHOD_FIELD_LEVEL);
0931:                Cl cl = getCl(fullName.substring(0, pos));
0932:                if (null != cl) {
0933:                    return cl
0934:                            .getMethod(fullName.substring(pos + 1), descriptor);
0935:                }
0936:                return null;
0937:            }
0938:
0939:            /** Get field in tree from the fully qualified name.
0940:             * @param fullName the fully qualified field name
0941:             * @return field item in the tree; null if the element is not found
0942:             * @throws IllegalStateException if an error exists inside the tree
0943:             */
0944:            public Fd getFd(String fullName) throws IllegalStateException {
0945:                // Split into class and field names
0946:                int pos = fullName.lastIndexOf(METHOD_FIELD_LEVEL);
0947:                Cl cl = getCl(fullName.substring(0, pos));
0948:                if (null != cl) {
0949:                    return cl.getField(fullName.substring(pos + 1));
0950:                }
0951:                return null;
0952:            }
0953:
0954:            /** Mapping for fully qualified class name.
0955:             * @param className the fully qualified class name to map
0956:             * @return the mapped class name
0957:             * @see NameMapper#mapClass
0958:             */
0959:            public String mapClass(String className) {
0960:                // Check for array -- requires special handling
0961:                if (className.length() > 0 && className.charAt(0) == '[') {
0962:                    StringBuffer newName = new StringBuffer();
0963:                    int i = 0;
0964:                    while (i < className.length()) {
0965:                        char ch = className.charAt(i++);
0966:                        switch (ch) {
0967:                        case '[':
0968:                        case ';':
0969:                            newName.append(ch);
0970:                            break;
0971:
0972:                        case 'L':
0973:                            newName.append(ch);
0974:                            int pos = className.indexOf(';', i);
0975:                            if (pos < 0) {
0976:                                throw new IllegalStateException(
0977:                                        "Invalid class name encountered: "
0978:                                                + className);
0979:                            }
0980:                            newName
0981:                                    .append(mapClass(className
0982:                                            .substring(i, pos)));
0983:                            i = pos;
0984:                            break;
0985:
0986:                        default:
0987:                            return className;
0988:                        }
0989:                    }
0990:                    return newName.toString();
0991:                } else {
0992:                    Cl cl = getCl(className);
0993:                    return cl != null ? cl.getFullOutName() : className;
0994:                }
0995:            }
0996:
0997:            /** Mapping for method name, of fully qualified class.
0998:             * @param className the class name
0999:             * @param methodName the method name
1000:             * @param descriptor the method descriptor
1001:             * @return mapped name; null if no mapping is found
1002:             * @see NameMapper#mapMethod
1003:             */
1004:            public String mapMethod(String className, String methodName,
1005:                    String descriptor) {
1006:                if (null != className && !className.equals("")) {
1007:                    Cl cl = getCl(className);
1008:                    if (null != cl) {
1009:                        Md md = cl.getMethod(methodName, descriptor);
1010:                        if (null != md) {
1011:                            return md.getOutName();
1012:                        } else {
1013:                            // Check whether the method is defined in the super class, necessary
1014:                            // when classes are compiled with "-target 1.[234]"
1015:                            // "-target 1.1", the default setting for the javac compiler from
1016:                            // JDK <1.4, lets the method reference directly point to the super
1017:                            // class where it is defined, whereby the others use a reference
1018:                            // to the class itself where the method is used.
1019:                            String retVal = mapMethod(cl.getSuperclass(),
1020:                                    methodName, descriptor);
1021:                            if (null != retVal)
1022:                                return retVal;
1023:                            // try to search whether the method is defined in implemented
1024:                            // interfaces
1025:                            String[] interfaces = cl.getSuperInterfaces();
1026:                            if (null != interfaces) {
1027:                                for (int i = 0; i < interfaces.length; i++) {
1028:                                    retVal = mapMethod(interfaces[i],
1029:                                            methodName, descriptor);
1030:                                    if (null != retVal)
1031:                                        return retVal;
1032:                                }
1033:                            }
1034:                        }
1035:                    }
1036:                }
1037:                return null;
1038:            }
1039:
1040:            /** Mapping for field name, of fully qualified class.
1041:             * @param className the class name
1042:             * @param fieldName the field name
1043:             * @return mapped field name; null if no mapping is found
1044:             * @see NameMapper#mapField
1045:             */
1046:            public String mapField(String className, String fieldName) {
1047:                if (null != className && !className.equals("")) {
1048:                    Cl cl = getCl(className);
1049:                    if (null != cl) {
1050:                        Fd fd = cl.getField(fieldName);
1051:                        if (null != fd) {
1052:                            return fd.getOutName();
1053:                        } else {
1054:                            // Check whether the field is defined in the super class, necessary
1055:                            // when classes are compiled with "-target 1.[234]"
1056:                            // "-target 1.1", the default setting for the javac compiler from
1057:                            // JDK <1.4, lets the field reference directly point to the super
1058:                            // class where it is defined, whereby the others use a reference
1059:                            // to the class itself where the field is used.
1060:                            String retVal = mapField(cl.getSuperclass(),
1061:                                    fieldName);
1062:                            if (null != retVal)
1063:                                return retVal;
1064:                            // try to search whether the field is defined in implemented
1065:                            // interfaces
1066:                            String[] interfaces = cl.getSuperInterfaces();
1067:                            if (null != interfaces) {
1068:                                for (int i = 0; i < interfaces.length; i++) {
1069:                                    retVal = mapField(interfaces[i], fieldName);
1070:                                    if (null != retVal)
1071:                                        return retVal;
1072:                                }
1073:                            }
1074:                        }
1075:                    }
1076:                }
1077:                return null;
1078:            }
1079:
1080:            /** Mapping for descriptor of field or method.
1081:             * @param descriptor the descriptor to map
1082:             * @return mapped descriptor string
1083:             * @see NameMapper#mapDescriptor
1084:             */
1085:            public String mapDescriptor(String descriptor) {
1086:                // Pass everything through unchanged, except for the String between
1087:                // 'L' and ';' -- this is passed through mapClass(String)
1088:                StringBuffer newDesc = new StringBuffer();
1089:                int i = 0;
1090:                while (i < descriptor.length()) {
1091:                    char ch = descriptor.charAt(i++);
1092:                    switch (ch) {
1093:                    case '[':
1094:                    case 'B':
1095:                    case 'C':
1096:                    case 'D':
1097:                    case 'F':
1098:                    case 'I':
1099:                    case 'J':
1100:                    case 'S':
1101:                    case 'Z':
1102:                    case 'V':
1103:                    case '(':
1104:                    case ')':
1105:                    case ';':
1106:                        newDesc.append(ch);
1107:                        break;
1108:
1109:                    case 'L':
1110:                        newDesc.append(ch);
1111:                        int pos = descriptor.indexOf(';', i);
1112:                        if (pos < 0) {
1113:                            throw new IllegalStateException(
1114:                                    "Invalid descriptor string encountered.");
1115:                        }
1116:                        newDesc.append(mapClass(descriptor.substring(i, pos)));
1117:                        i = pos;
1118:                        break;
1119:
1120:                    default:
1121:                        throw new IllegalStateException(
1122:                                "Invalid descriptor string encountered.");
1123:                    }
1124:                }
1125:                return newDesc.toString();
1126:            }
1127:
1128:            /** Dump the content of the class tree to the specified file (used for
1129:             * logging).
1130:             */
1131:            public void dump() {
1132:                logger.log(Log.INFO, "Dumping class tree...");
1133:                dumpFrequencyCount();
1134:                dumpIgnoreStatements();
1135:                dumpRemoteClasses();
1136:                dumpAutoCorrectedClasses();
1137:                dumpSerializables();
1138:                dumpReservedNames();
1139:                dumpNameMappings();
1140:            }
1141:
1142:            /** Dupms the name frequency count to the log file.
1143:             */
1144:            private void dumpFrequencyCount() {
1145:    logger.log(Log.VERBOSE, "Calculating name frequency count");
1146:    logfile.println();
1147:    logfile.println();
1148:    logfile.println();
1149:    logfile.println("#");
1150:    logfile.println("# Obfuscated name overloading frequency:");
1151:    logfile.println("#");
1152:    // Compute total use count
1153:    int totalUseCount = 0;
1154:    for (Enumeration useCountEnum = NameMaker.getUseCounts(); useCountEnum.hasMoreElements(); ) {
1155:      totalUseCount += ((Integer)useCountEnum.nextElement()).intValue() + 1;
1156:    }
1157:    
1158:    // Log the individual use counts for names
1159:    if (totalUseCount != 0) {
1160:      int sumPercent = 0;
1161:      int sumUseCount = 0;
1162:      Vector sort = new Vector();
1163:      for (Enumeration nameEnum = NameMaker.getNames(), useCountEnum = NameMaker.getUseCounts(); nameEnum.hasMoreElements(); ) {
1164:        String name = (String)nameEnum.nextElement();
1165:        int useCount = ((Integer)useCountEnum.nextElement()).intValue() + 1;
1166:        int percent = 100 * useCount / totalUseCount;
1167:        if (percent != 0) {
1168:          sort.addElement(new SortElement(name, useCount));
1169:          sumUseCount += useCount;
1170:          sumPercent += percent;
1171:        }
1172:      }
1173:      while (sort.size() != 0) {
1174:        SortElement se = null;
1175:        int largestUseCount = 0;
1176:        for (Enumeration enum = sort.elements(); enum.hasMoreElements(); ) {
1177:          SortElement this Se = (SortElement)enum.nextElement();
1178:          if (this Se.useCount >= largestUseCount) {
1179:            se = this Se;
1180:            largestUseCount = se.useCount;
1181:          }
1182:        }
1183:        sort.removeElement(se);
1184:        logfile.println("#  '" + se.name + "'   \tused " + se.useCount + " times\t(" + Integer.toString(100 * se.useCount / totalUseCount) + "%)");
1185:      }
1186:      
1187:      // Log the remainder percentage
1188:      logfile.println("#  Other names (each used in <1% of mappings) used a total of "
1189:      + Integer.toString(totalUseCount - sumUseCount)
1190:      + " times (" + Integer.toString(100 - sumPercent) + "%)");
1191:      logfile.println("#");
1192:    }
1193:  }
1194:
1195:            class SortElement {
1196:                int useCount;
1197:                String name;
1198:
1199:                SortElement(String name, int useCount) {
1200:                    this .useCount = useCount;
1201:                    this .name = name;
1202:                }
1203:            }
1204:
1205:            /** Write all ignore statements to the log file.
1206:             */
1207:            private void dumpIgnoreStatements() {
1208:                // check if there are ".ignore" statements
1209:                if (!patternsIgnoreDefault.isEmpty()
1210:                        || !patternsIgnorePackage.isEmpty()
1211:                        || !patternsIgnoreClass.isEmpty()
1212:                        || !patternsIgnoreMethod.isEmpty()
1213:                        || !patternsIgnoreField.isEmpty()) {
1214:                    logger.log(Log.VERBOSE,
1215:                            "Creating list with ignore statements");
1216:                    // if yes write them to the log file
1217:                    logfile.println();
1218:                    logfile.println();
1219:                    logfile.println();
1220:                    logfile.println("#");
1221:                    logfile.println("# Ignored from obfuscation:");
1222:                    logfile.println("#");
1223:
1224:                    // write all tree elements that should be ignored to the log file
1225:                    walkTree(new TreeAction() {
1226:                        public void packageAction(Pk pk) {
1227:                            defaultAction(pk);
1228:                        }
1229:
1230:                        public void classAction(Cl cl) {
1231:                            defaultAction(cl);
1232:                        }
1233:
1234:                        public void methodAction(Md md) {
1235:                            defaultAction(md);
1236:                        }
1237:
1238:                        public void fieldAction(Fd fd) {
1239:                            defaultAction(fd);
1240:                        }
1241:
1242:                        public void defaultAction(TreeItem ti) {
1243:                            if (ti.canIgnoreElement()) {
1244:                                if (null == ti.getParent()
1245:                                        || !ti.getParent().canIgnoreElement()) {
1246:                                    if (ti instanceof  Pk) {
1247:                                        logfile
1248:                                                .println(ScriptConstants.DIRECTIVE_IGNORE_PACKAGE
1249:                                                        + " "
1250:                                                        + ti.getFullInName());
1251:                                    } else if (ti instanceof  Cl) {
1252:                                        logfile
1253:                                                .println(ScriptConstants.DIRECTIVE_IGNORE_CLASS
1254:                                                        + "   "
1255:                                                        + ti.getFullInName());
1256:                                    } else if (ti instanceof  Md) {
1257:                                        logfile
1258:                                                .println(ScriptConstants.DIRECTIVE_IGNORE_METHOD
1259:                                                        + "  "
1260:                                                        + ti.getFullInName()
1261:                                                        + " "
1262:                                                        + ((Md) ti)
1263:                                                                .getDescriptor());
1264:                                    } else if (ti instanceof  Fd) {
1265:                                        logfile
1266:                                                .println(ScriptConstants.DIRECTIVE_IGNORE_FIELD
1267:                                                        + "   "
1268:                                                        + ti.getFullInName()
1269:                                                        + " "
1270:                                                        + ((Fd) ti)
1271:                                                                .getDescriptor());
1272:                                    } else {
1273:                                        // should never happen, only if there's an error in the internal
1274:                                        // data structures
1275:                                        logfile
1276:                                                .println(ScriptConstants.DIRECTIVE_IGNORE
1277:                                                        + "         "
1278:                                                        + ti.getFullInName());
1279:                                    }
1280:                                }
1281:                            }
1282:                        }
1283:                    });
1284:                } else {
1285:                    logger
1286:                            .log(Log.VERBOSE,
1287:                                    "Skipping creating list with ignore statements (no elements available)");
1288:                }
1289:            }
1290:
1291:            /** Write the list of processed remote classes to the log file.
1292:             */
1293:            private void dumpRemoteClasses() {
1294:                if (canUseRmicClasses()) {
1295:                    logger.log(Log.VERBOSE,
1296:                            "Generating list of processed remote classes");
1297:                    logfile.println();
1298:                    logfile.println();
1299:                    logfile.println();
1300:                    logfile.println("#");
1301:                    logfile.println("# remote classes:");
1302:                    logfile.println("#");
1303:
1304:                    for (int i = 0; i < remoteClasses.size(); i++) {
1305:                        Cl classItem = (Cl) remoteClasses.elementAt(i);
1306:                        logfile.println("# class " + classItem.getFullInName());
1307:                        logfile.println("#    -> " + classItem.getOutName());
1308:                    }
1309:                } else {
1310:                    logger
1311:                            .log(Log.VERBOSE,
1312:                                    "Skipping generating list of processed remote classes");
1313:                }
1314:            }
1315:
1316:            /** Write the list of classes that were used in hardcoded references to the
1317:             * log file.
1318:             */
1319:            private void dumpAutoCorrectedClasses() {
1320:                if (canAutoCorrectClassNames()) {
1321:                    logger
1322:                            .log(Log.VERBOSE,
1323:                                    "Generating list of classes used in hardcoded references");
1324:                    logfile.println();
1325:                    logfile.println();
1326:                    logfile.println();
1327:                    logfile.println("#");
1328:                    logfile
1329:                            .println("# The following classes are used in hardcoded references:");
1330:                    logfile.println("#");
1331:                    Iterator iter = hardcodedReferences.iterator();
1332:                    while (iter.hasNext()) {
1333:                        String str = (String) iter.next();
1334:                        if (null != str) {
1335:                            TreeItem ti = findClass(str);
1336:                            if (null == ti) {
1337:                                logfile.log("# Warning: cannot find class "
1338:                                        + str);
1339:                            } else {
1340:                                logfile.println("# retaining class "
1341:                                        + ti.getFullInName());
1342:                            }
1343:                        }
1344:                    }
1345:                } else {
1346:                    logger
1347:                            .log(Log.VERBOSE,
1348:                                    "Skipping generating list of classes used in hardcoded references");
1349:                }
1350:            }
1351:
1352:            /** Write the list of serializable methods and fields found to the log file.
1353:             */
1354:            private void dumpSerializables() {
1355:                logger.log(Log.VERBOSE,
1356:                        "Writing list of serializable methods and fields");
1357:                logfile.println();
1358:                logfile.println();
1359:                logfile.println();
1360:                logfile.println("#");
1361:                logfile
1362:                        .println("# The following fields and methods are used in serializable classes");
1363:                logfile
1364:                        .println("# and are checked whether they should be marked for retention or not:");
1365:                logfile.println("#");
1366:
1367:                int i;
1368:                // log all serializable fields
1369:                for (i = 0; i < serializableFields.size(); i++) {
1370:                    Fd fd = (Fd) serializableFields.elementAt(i);
1371:                    if (isSerializableClass((Cl) fd.getParent())) {
1372:                        logfile.print("# field marked:      ");
1373:                    } else {
1374:                        logfile.print("# field not marked:  ");
1375:                    }
1376:                    logfile.println(fd.getFullInName() + " "
1377:                            + fd.getDescriptor());
1378:                }
1379:
1380:                // add all additional methods
1381:                for (i = 0; i < serializableMethods.size(); i++) {
1382:                    Md md = (Md) serializableMethods.elementAt(i);
1383:                    if (isSerializableClass((Cl) md.getParent())) {
1384:                        logfile.print("# method marked:     ");
1385:                    } else {
1386:                        logfile.print("# method not marked: ");
1387:                    }
1388:                    logfile.println(md.getFullInName() + " "
1389:                            + md.getDescriptor());
1390:                }
1391:            }
1392:
1393:            /** Write the list of names prevented from being obfuscated to the log file.
1394:             */
1395:            private void dumpReservedNames() {
1396:                logger.log(Log.VERBOSE, "Writing list of reserved names");
1397:                // write all names that should be reserved from obfuscation to the log file
1398:                logfile.println();
1399:                logfile.println();
1400:                logfile.println();
1401:                logfile.println("#");
1402:                logfile
1403:                        .println("# Full list of names reserved from obfuscation:");
1404:                logfile.println("#");
1405:
1406:                walkTree(new TreeAction() {
1407:                    public void classAction(Cl cl) {
1408:                        if (!cl.canIgnoreElement() && cl.isFromScript()) {
1409:                            logfile.println(ScriptConstants.DIRECTIVE_CLASS
1410:                                    + "  " + cl.getFullInName());
1411:                        }
1412:                    }
1413:
1414:                    public void methodAction(Md md) {
1415:                        if (!md.canIgnoreElement() && md.isFromScript()) {
1416:                            logfile.println(ScriptConstants.DIRECTIVE_METHOD
1417:                                    + " " + md.getFullInName() + " "
1418:                                    + md.getDescriptor());
1419:                        }
1420:                    }
1421:
1422:                    public void fieldAction(Fd fd) {
1423:                        if (!fd.canIgnoreElement() && fd.isFromScript()) {
1424:                            logfile.println(ScriptConstants.DIRECTIVE_FIELD
1425:                                    + "  " + fd.getFullInName() + " "
1426:                                    + fd.getDescriptor());
1427:                        }
1428:                    }
1429:
1430:                    public void packageAction(Pk pk) {
1431:                        // No action
1432:                    }
1433:                });
1434:            }
1435:
1436:            /** Write the name mapping table to the log file.
1437:             */
1438:            private void dumpNameMappings() {
1439:                logger.log(Log.VERBOSE, "Writing the name mapping table");
1440:                logfile.println();
1441:                logfile.println();
1442:                logfile.println();
1443:                logfile.println("#");
1444:                logfile
1445:                        .println("# Obfuscated name mappings (some of these may be unchanged due to polymorphism");
1446:                logfile.println("# constraints):");
1447:                logfile.println("#");
1448:
1449:                // now write the obfuscated names to the log file
1450:                walkTree(new TreeAction() {
1451:                    public void classAction(Cl cl) {
1452:                        if (!cl.canIgnoreElement() && !cl.isFromScript()) {
1453:                            logfile.println(ScriptConstants.DIRECTIVE_CLASS_MAP
1454:                                    + "   " + cl.getFullInName() + " "
1455:                                    + cl.getOutName());
1456:                        }
1457:                    }
1458:
1459:                    public void methodAction(Md md) {
1460:                        if (!md.canIgnoreElement() && !md.isFromScript()) {
1461:                            logfile
1462:                                    .println(ScriptConstants.DIRECTIVE_METHOD_MAP
1463:                                            + "  "
1464:                                            + md.getFullInName()
1465:                                            + " "
1466:                                            + md.getDescriptor()
1467:                                            + " "
1468:                                            + md.getOutName());
1469:                        }
1470:                    }
1471:
1472:                    public void fieldAction(Fd fd) {
1473:                        if (!fd.canIgnoreElement() && !fd.isFromScript()) {
1474:                            logfile.println(ScriptConstants.DIRECTIVE_FIELD_MAP
1475:                                    + "   " + fd.getFullInName() + " "
1476:                                    + fd.getOutName());
1477:                        }
1478:                    }
1479:
1480:                    public void packageAction(Pk pk) {
1481:                        if (!pk.canIgnoreElement() && !pk.isFromScript()
1482:                                && pk.getFullInName().length() > 0) {
1483:                            logfile.println();
1484:                            logfile
1485:                                    .println(ScriptConstants.DIRECTIVE_PACKAGE_MAP
1486:                                            + " "
1487:                                            + pk.getFullInName()
1488:                                            + " "
1489:                                            + pk.getOutName());
1490:                        }
1491:                    }
1492:                });
1493:            }
1494:
1495:            /** Walk the whole tree taking action once only on each package level, class,
1496:             * method and field.
1497:             * @param ta set of actions to be performed on tree elements
1498:             */
1499:            public void walkTree(TreeAction ta) {
1500:                walkTree(ta, getRootPackage());
1501:            }
1502:
1503:            /** Walk the given subtree taking action once only on each package level,
1504:             * class, method and field.
1505:             * @param ta set of actions to be performed on tree elements
1506:             * @param ti the head of the subtree
1507:             */
1508:            public void walkTree(TreeAction ta, TreeItem ti) {
1509:                if (ti instanceof  Pk) {
1510:                    Iterator packageIter = ((Pk) ti).getPackageIterator();
1511:                    ta.packageAction((Pk) ti);
1512:                    while (packageIter.hasNext()) {
1513:                        walkTree(ta, (TreeItem) packageIter.next());
1514:                    }
1515:                }
1516:                if (ti instanceof  Cl) {
1517:                    Iterator fieldIter = ((Cl) ti).getFieldIterator();
1518:                    Iterator methodIter = ((Cl) ti).getMethodIterator();
1519:                    ta.classAction((Cl) ti);
1520:                    while (fieldIter.hasNext()) {
1521:                        ta.fieldAction((Fd) fieldIter.next());
1522:                    }
1523:                    while (methodIter.hasNext()) {
1524:                        ta.methodAction((Md) methodIter.next());
1525:                    }
1526:                }
1527:                if (ti instanceof  PkCl) {
1528:                    Iterator classIter = ((PkCl) ti).getClassIterator();
1529:                    while (classIter.hasNext()) {
1530:                        walkTree(ta, (TreeItem) classIter.next());
1531:                    }
1532:                }
1533:            }
1534:
1535:            /** Adds a regular expression to the name pattern list which is used to
1536:             * prevent packages, classes etc. from being obfuscated.
1537:             * @param regex a regular expression
1538:             * @throws MalformedPatternException if an error occurs during regex compilation
1539:             */
1540:            public void addIgnoreDefaultRegex(String regex)
1541:                    throws MalformedPatternException {
1542:                addRegex(patternsIgnoreDefault, regex, null);
1543:            }
1544:
1545:            /** Adds a regular expression to the package name pattern list which is used
1546:             * to prevent packages from being obfuscated.
1547:             * @param regex a regular expression
1548:             * @throws MalformedPatternException if an error occurs during regex compilation
1549:             */
1550:            public void addIgnorePackageRegex(String regex)
1551:                    throws MalformedPatternException {
1552:                addRegex(patternsIgnorePackage, regex, null);
1553:            }
1554:
1555:            /** Adds a regular expression to the class name pattern list which is used
1556:             * to prevent classes from being obfuscated.
1557:             * @param regex a regular expression
1558:             * @throws MalformedPatternException if an error occurs during regex compilation
1559:             */
1560:            public void addIgnoreClassRegex(String regex)
1561:                    throws MalformedPatternException {
1562:                addRegex(patternsIgnoreClass, regex, null);
1563:            }
1564:
1565:            /** Adds a regular expression to the package name pattern list which is used
1566:             * to prevent method names from being obfuscated.
1567:             * @param entry a script file directive that contains the regular expression
1568:             * @throws MalformedPatternException if an error occurs during regex compilation
1569:             */
1570:            public void addIgnoreMethodRegex(ScriptEntry entry)
1571:                    throws MalformedPatternException {
1572:                addRegex(patternsIgnoreMethod, entry.getName(), entry);
1573:            }
1574:
1575:            /** Adds a regular expression to the package name pattern list which is used
1576:             * to prevent field names from being obfuscated.
1577:             * @param entry script file entry that contains the regular expression
1578:             * @throws MalformedPatternException if an error occurs during regex compilation
1579:             */
1580:            public void addIgnoreFieldRegex(ScriptEntry entry)
1581:                    throws MalformedPatternException {
1582:                addRegex(patternsIgnoreField, entry.getName(), entry);
1583:            }
1584:
1585:            /** Adds a regular expression to the name pattern list which is used to
1586:             * force packages, classes etc. to get obfuscated.
1587:             * @param regex a regular expression
1588:             * @throws MalformedPatternException if an error occurs during regex compilation
1589:             */
1590:            public void addObfuscateDefaultRegex(String regex)
1591:                    throws MalformedPatternException {
1592:                addRegex(patternsObfuscateDefault, regex, null);
1593:            }
1594:
1595:            /** Adds a regular expression to the package name pattern list which is used
1596:             * to force packages to get obfuscated.
1597:             * @param regex a regular expression
1598:             * @throws MalformedPatternException if an error occurs during regex compilation
1599:             */
1600:            public void addObfuscatePackageRegex(String regex)
1601:                    throws MalformedPatternException {
1602:                addRegex(patternsObfuscatePackage, regex, null);
1603:            }
1604:
1605:            /** Adds a regular expression to the class name pattern list which is used
1606:             * to force classes to get obfuscated.
1607:             * @param regex a regular expression
1608:             * @throws MalformedPatternException if an error occurs during regex compilation
1609:             */
1610:            public void addObfuscateClassRegex(String regex)
1611:                    throws MalformedPatternException {
1612:                addRegex(patternsObfuscateClass, regex, null);
1613:            }
1614:
1615:            /** Adds a regular expression to the package name pattern list which is used
1616:             * to force method names to get obfuscated.
1617:             * @param entry a script file directive that contains the regular expression
1618:             * @throws MalformedPatternException if an error occurs during regex compilation
1619:             */
1620:            public void addObfuscateMethodRegex(ScriptEntry entry)
1621:                    throws MalformedPatternException {
1622:                addRegex(patternsIgnoreMethod, entry.getName(), entry);
1623:            }
1624:
1625:            /** Adds a regular expression to the package name pattern list which is used
1626:             * to force field names to get obfuscated.
1627:             * @param entry script file entry that contains the regular expression
1628:             * @throws MalformedPatternException if an error occurs during regex compilation
1629:             */
1630:            public void addObfuscateFieldRegex(ScriptEntry entry)
1631:                    throws MalformedPatternException {
1632:                addRegex(patternsObfuscateField, entry.getName(), entry);
1633:            }
1634:
1635:            /** Adds a regular expression to the given map if it isn't already contained
1636:             * in it.
1637:             * @param map the map that holds precompiled regular expressions
1638:             * @param regex a regular expression
1639:             * @param info an object that holds additional informations
1640:             * @throws MalformedPatternException if an error occurs during regex compilation
1641:             * @see #compileRegex
1642:             */
1643:            private void addRegex(Map map, String regex, Object info)
1644:                    throws MalformedPatternException {
1645:                if (!map.containsKey(regex)) {
1646:                    map.put(regex, new KeyValue(compileRegex(regex), info));
1647:                } else {
1648:                    logger.log("Warning: Duplicate regex pattern: '" + regex
1649:                            + "'");
1650:                }
1651:            }
1652:
1653:            /** Corrects the regular expression and compiles it into a data structure
1654:             * that can be used by a pattern matcher implementation to perform pattern
1655:             * matching.
1656:             * @param regex a regular expression
1657:             * @return a pattern instance constituting the compiled regular expression
1658:             * @throws MalformedPatternException If the compiled expression does not
1659:             * conform to the grammar understood by the PatternCompiler or if some other
1660:             * error in the expression is encountered.
1661:             */
1662:            private Pattern compileRegex(String regex)
1663:                    throws MalformedPatternException {
1664:                StringBuffer sb = new StringBuffer();
1665:                // Fix the regular expression so that it always has the form ^...$
1666:                // To be compatible with RetroGuard and to form valid regular expressions
1667:                // strings that end with ".../*" are corrected so they end with ".../.*",
1668:                // and occurrences of a '$' sign inside a string are replaced by '\$'
1669:                // to correctly match inner classes/elements.
1670:
1671:                // let the regex always start with '^'
1672:                if (!regex.startsWith("^")) {
1673:                    sb.append('^');
1674:                }
1675:
1676:                // replace dollar signs by '\$'
1677:                int i = 0;
1678:                int pos = regex.indexOf('$');
1679:                while (pos > 0) {
1680:                    if (regex.charAt(pos - 1) != '\\') {
1681:                        sb.append(regex.substring(i, pos));
1682:                        sb.append("\\$");
1683:                        i = pos + 1;
1684:                    }
1685:                    pos = regex.indexOf('$', pos + 1);
1686:                }
1687:
1688:                // replace "/*" string end by "/.*"
1689:                if (regex.endsWith("/*")) {
1690:                    sb.append(regex.substring(i, regex.length() - 2));
1691:                    sb.append("/.*");
1692:                } else {
1693:                    sb.append(regex.substring(i));
1694:                }
1695:
1696:                // let the regex end with '$' to match the line end
1697:                if (!regex.endsWith("$")) {
1698:                    sb.append('$');
1699:                }
1700:                return patternCompiler.compile(sb.toString());
1701:            }
1702:
1703:            /** Checks whether there is a regular expression in the default pattern list
1704:             * that matches a given string.
1705:             * @param str a string to check
1706:             * @return true if at least one regular expression matches the given string;
1707:             * false else
1708:             * @see #addIgnoreDefaultRegex
1709:             */
1710:            private boolean matchesIgnoreDefaultRegex(String str) {
1711:                return matchesRegex(patternsIgnoreDefault, str);
1712:            }
1713:
1714:            /** Checks whether there is a regular expression in the package name pattern
1715:             * list that matches a given string.
1716:             * @param str a package name to check
1717:             * @return true if at least one regular expression matches the given string;
1718:             * false else
1719:             * @see #addIgnorePackageRegex
1720:             */
1721:            private boolean matchesIgnorePackageRegex(String str) {
1722:                return matchesRegex(patternsIgnorePackage, str);
1723:            }
1724:
1725:            /** Checks whether there is a regular expression in the class name pattern
1726:             * list that matches a given string.
1727:             * @param str a class name to check
1728:             * @return true if at least one regular expression matches the given string;
1729:             * false else
1730:             * @see #addIgnoreClassRegex
1731:             */
1732:            private boolean matchesIgnoreClassRegex(String str) {
1733:                return matchesRegex(patternsIgnoreClass, str);
1734:            }
1735:
1736:            /** Checks whether there is a regular expression in the method name pattern
1737:             * list that matches a given string.
1738:             * @param str a method name to check
1739:             * @return true if at least one regular expression matches the given string;
1740:             * false else
1741:             * @see #addIgnoreMethodRegex
1742:             */
1743:            private boolean matchesIgnoreMethodRegex(String str) {
1744:                return matchesRegex(patternsIgnoreMethod, str);
1745:            }
1746:
1747:            /** Checks whether there is a regular expression in the field name pattern
1748:             * list that matches a given string.
1749:             * @param str a field name to check
1750:             * @return true if at least one regular expression matches the given string;
1751:             * false else
1752:             * @see #addIgnoreFieldRegex
1753:             */
1754:            private boolean matchesIgnoreFieldRegex(String str) {
1755:                return matchesRegex(patternsIgnoreField, str);
1756:            }
1757:
1758:            /** Checks whether there is a regular expression in the default pattern list
1759:             * that matches a given string.
1760:             * @param str a string to check
1761:             * @return true if at least one regular expression matches the given string;
1762:             * false else
1763:             * @see #addObfuscateDefaultRegex
1764:             */
1765:            private boolean matchesObfuscateDefaultRegex(String str) {
1766:                return matchesRegex(patternsObfuscateDefault, str);
1767:            }
1768:
1769:            /** Checks whether there is a regular expression in the package name pattern
1770:             * list that matches a given string.
1771:             * @param str a package name to check
1772:             * @return true if at least one regular expression matches the given string;
1773:             * false else
1774:             * @see #addObfuscatePackageRegex
1775:             */
1776:            private boolean matchesObfuscatePackageRegex(String str) {
1777:                return matchesRegex(patternsObfuscatePackage, str);
1778:            }
1779:
1780:            /** Checks whether there is a regular expression in the class name pattern
1781:             * list that matches a given string.
1782:             * @param str a class name to check
1783:             * @return true if at least one regular expression matches the given string;
1784:             * false else
1785:             * @see #addObfuscateClassRegex
1786:             */
1787:            private boolean matchesObfuscateClassRegex(String str) {
1788:                return matchesRegex(patternsObfuscateClass, str);
1789:            }
1790:
1791:            /** Checks whether there is a regular expression in the method name pattern
1792:             * list that matches a given string.
1793:             * @param str a method name to check
1794:             * @return true if at least one regular expression matches the given string;
1795:             * false else
1796:             * @see #addObfuscateMethodRegex
1797:             */
1798:            private boolean matchesObfuscateMethodRegex(String str) {
1799:                return matchesRegex(patternsObfuscateMethod, str);
1800:            }
1801:
1802:            /** Checks whether there is a regular expression in the field name pattern
1803:             * list that matches a given string.
1804:             * @param str a field name to check
1805:             * @return true if at least one regular expression matches the given string;
1806:             * false else
1807:             * @see #addObfuscateFieldRegex
1808:             */
1809:            private boolean matchesObfuscateFieldRegex(String str) {
1810:                return matchesRegex(patternsObfuscateField, str);
1811:            }
1812:
1813:            /** Checks whether a string is matched by a regular expression in the given
1814:             * map.
1815:             * @param map the map that holds precompiled regular expressions
1816:             * @param str the string to verify
1817:             * @return true if a regular expression matches the given string; false else
1818:             */
1819:            private boolean matchesRegex(Map map, String str) {
1820:                Iterator iter = map.values().iterator();
1821:                while (iter.hasNext()) {
1822:                    KeyValue kv = (KeyValue) iter.next();
1823:                    Pattern regex = (Pattern) kv.getKey();
1824:                    if (patternMatcher.contains(str, regex)) {
1825:                        return true;
1826:                    }
1827:                }
1828:                return false;
1829:            }
1830:
1831:            /** Walk through the tree and mark all elements that must be obfuscated and
1832:             * all elements that should be completely ignored in the obfuscation step.
1833:             */
1834:            public void parseObfuscateAndIgnoreList() {
1835:                logger
1836:                        .log(Log.VERBOSE,
1837:                                "Parsing list of elements to obfuscate and to ignore...");
1838:                walkTree(new TreeAction() {
1839:                    public void packageAction(Pk pk) {
1840:                        defaultAction(pk);
1841:                    }
1842:
1843:                    public void classAction(Cl cl) {
1844:                        defaultAction(cl);
1845:                    }
1846:
1847:                    public void methodAction(Md md) {
1848:                        defaultAction(md);
1849:                    }
1850:
1851:                    public void fieldAction(Fd fd) {
1852:                        defaultAction(fd);
1853:                    }
1854:
1855:                    public void defaultAction(TreeItem ti) {
1856:                        String name = ti.getFullInName();
1857:                        if (null != name && !name.equals("")) {
1858:                            if ((null != ti.getParent() && ti.getParent()
1859:                                    .canForceObfuscate())
1860:                                    || (ti instanceof  Cl && matchesObfuscateClassRegex(name))
1861:                                    || (ti instanceof  Pk && matchesObfuscatePackageRegex(name))
1862:                                    || (ti instanceof  Md && matchesObfuscateMethodRegex(name))
1863:                                    || (ti instanceof  Fd && matchesObfuscateFieldRegex(name))
1864:                                    || matchesObfuscateDefaultRegex(name)) {
1865:                                ti.setForceObfuscate(true);
1866:                                ti.setIgnoreElement(false);
1867:                            } else {
1868:                                ti.setForceObfuscate(false);
1869:                            }
1870:                            // a tree element can only be ignored if it can be obfuscated
1871:                            if (!ti.canForceObfuscate()) {
1872:                                if ((null != ti.getParent() && ti.getParent()
1873:                                        .canIgnoreElement())
1874:                                        || (ti instanceof  Cl && matchesIgnoreClassRegex(name))
1875:                                        || (ti instanceof  Pk && matchesIgnorePackageRegex(name))
1876:                                        || (ti instanceof  Md && matchesIgnoreMethodRegex(name))
1877:                                        || (ti instanceof  Fd && matchesIgnoreFieldRegex(name))
1878:                                        || matchesIgnoreDefaultRegex(name)) {
1879:                                    ti.setIgnoreElement(true);
1880:                                    retainItem(ti);
1881:                                } else {
1882:                                    ti.setIgnoreElement(false);
1883:                                }
1884:                                // if the current tree element is a class or a packege that should
1885:                                // retain its name also preserve the names of all super elements
1886:                                if (ti.canIgnoreElement()
1887:                                        && (ti instanceof  Pk || ti instanceof  Cl)) {
1888:                                    retainHierarchy(ti.getParent());
1889:                                }
1890:                            }
1891:                        }
1892:                    }
1893:                });
1894:            }
1895:
1896:            /** Walk through the tree and check which classes implement java.rmi.Remote
1897:             * or java.rmi.server.Skeleton.
1898:             */
1899:            public void markRemoteClasses() {
1900:                if (canUseRmicClasses()) {
1901:                    logger.log(Log.VERBOSE, "Mark remote classes...");
1902:                    walkTree(new TreeAction() {
1903:                        public void classAction(Cl cl) {
1904:                            if (isRemoteClass(cl)) {
1905:                                logger.log(Log.DEBUG, "Remote class found: "
1906:                                        + cl.getFullInName());
1907:                                remoteClasses.addElement(cl);
1908:                            }
1909:                        }
1910:
1911:                        public void packageAction(Pk pk) {
1912:                        }
1913:
1914:                        public void methodAction(Md md) {
1915:                        }
1916:
1917:                        public void fieldAction(Fd fd) {
1918:                        }
1919:                    });
1920:                } else {
1921:                    logger.log(Log.VERBOSE, "Skipping marking remote classes");
1922:                }
1923:            }
1924:
1925:            /** Checks whether the given class or one of its super classes implement the
1926:             * java.rmi.Remote or java.rmi.server.Skeleton interface.
1927:             * @param cl the class to verify
1928:             * @return true if the class implements the Remote or Skeleton interface;
1929:             * false else
1930:             */
1931:            private boolean isRemoteClass(Cl cl) {
1932:                if (null == cl)
1933:                    return false;
1934:                if (cl.isRemoteClass())
1935:                    return true;
1936:
1937:                // check the implemented interfaces
1938:                String[] interfaces = cl.getSuperInterfaces();
1939:                boolean result = false;
1940:                int i = 0;
1941:                while (i < interfaces.length) {
1942:                    // check whether the current interface name is one of the remote interfaces
1943:                    if (interfaces[i].equals(REMOTE_INTERFACE)
1944:                            || interfaces[i].equals(SKELETON_INTERFACE)) {
1945:                        // yes -> mark the class as being a remote class
1946:                        result = true;
1947:                        break;
1948:                    }
1949:                    // check whether the referenced interface exists in the tree
1950:                    Cl interfaceCl = getCl(interfaces[i]);
1951:                    if (null != interfaceCl) {
1952:                        // the interface exists in the tree -> check whether it is a remote one
1953:                        if (isRemoteClass(interfaceCl)) {
1954:                            // yes -> mark the class as being a remote class
1955:                            result = true;
1956:                            break;
1957:                        }
1958:                    } else {
1959:                        // the class doesn't exist in the tree
1960:                        // -> check whether the class is accessible via the JVM
1961:                        if (isRemoteClass(interfaces[i])) {
1962:                            // the JVM-accessible class is a remote class -> mark the current class
1963:                            result = true;
1964:                            break;
1965:                        }
1966:                    }
1967:                    i++;
1968:                }
1969:                // If we don't have a result so far check whether the super class is a
1970:                // remote class
1971:                if (!result) {
1972:                    Cl super Cl = getCl(cl.getSuperclass());
1973:                    if (null == super Cl) {
1974:                        // the super class doesn't exist in the tree -> query the JVM
1975:                        result = isRemoteClass(cl.getSuperclass());
1976:                    } else {
1977:                        // otherwise query the internal name database
1978:                        result = isRemoteClass(super Cl);
1979:                    }
1980:                }
1981:                // if the class implements the Remote or Skeleton interface mark it as
1982:                // being a remote class
1983:                if (true == result) {
1984:                    cl.setRemoteClass(true);
1985:                }
1986:                return result;
1987:            }
1988:
1989:            /** Checks whether the given class or one of its super classes implement the
1990:             * java.rmi.Remote or java.rmi.server.Skeleton interface.
1991:             * @param name the name of the class to verify
1992:             * @return true if the class implements the Remote or Skeleton interface;
1993:             * false else
1994:             */
1995:            private boolean isRemoteClass(String name) {
1996:                // try to receive a Class object from the running JVM
1997:                try {
1998:                    Class cls = Class.forName(name.replace('/', '.'), false,
1999:                            getClass().getClassLoader());
2000:                    return isRemoteClass(cls);
2001:                } catch (ClassNotFoundException cnfex) {
2002:                    // if the referenced class doesn't exist we don't care so far
2003:                }
2004:                return false;
2005:            }
2006:
2007:            /** Checks whether the given class or one of its super classes implement the
2008:             * java.rmi.Remote or java.rmi.server.Skeleton interface.
2009:             * @param cls the class to verify
2010:             * @return true if the class implements the Remote or Skeleton interface;
2011:             * false else
2012:             */
2013:            private boolean isRemoteClass(Class cls) {
2014:                if (null == cls) {
2015:                    return false;
2016:                }
2017:
2018:                if (cls.isInterface()
2019:                        && (cls.getName().equals(REMOTE_INTERFACE_CLASS) || cls
2020:                                .getName().equals(SKELETON_INTERFACE_CLASS))) {
2021:                    return true;
2022:                }
2023:                // check whether the super class implements the Remote or Skeleton interface
2024:                if (isRemoteClass(cls.getSuperclass())) {
2025:                    return true;
2026:                }
2027:                // check the implemented interfaces
2028:                Class[] interfaces = cls.getInterfaces();
2029:                for (int i = 0; i < interfaces.length; i++) {
2030:                    if (isRemoteClass(interfaces[i])) {
2031:                        return true;
2032:                    }
2033:                }
2034:                return false;
2035:            }
2036:
2037:            /** Obfuscates the names of special classes (such as classes created by rmic)
2038:             * so that they correspond to their original classes.
2039:             */
2040:            public void retainRemoteClasses() {
2041:                if (canUseRmicClasses()) {
2042:                    logger.log(Log.VERBOSE, "Processing remote classes...");
2043:                    for (int i = 0; i < remoteClasses.size(); i++) {
2044:                        Cl classItem = (Cl) remoteClasses.elementAt(i);
2045:                        String className = classItem.getFullInName();
2046:
2047:                        // only continue if we have a non-empty class name
2048:                        if (null != className && !className.equals("")) {
2049:                            String str = null;
2050:                            if (className.endsWith(STR_STUB)) {
2051:                                str = className.substring(0, className.length()
2052:                                        - STR_STUB.length());
2053:                            } else if (className.endsWith(STR_SKEL)) {
2054:                                str = className.substring(0, className.length()
2055:                                        - STR_SKEL.length());
2056:                            }
2057:                            // strip the rmic-generated suffix from the class name to receive the
2058:                            // original name
2059:                            if (null != str) {
2060:                                Cl originalClass = getCl(str);
2061:                                if (null != originalClass) {
2062:                                    String outName = originalClass.getOutName();
2063:                                    // now assign a new name to the rmic-generated class
2064:                                    if (className.endsWith(STR_STUB)) {
2065:                                        // if it's a stub class append "_Stub"
2066:                                        classItem
2067:                                                .setOutName(outName + STR_STUB);
2068:                                    } else {
2069:                                        // it it's a skeleton class append "_Skel"
2070:                                        classItem
2071:                                                .setOutName(outName + STR_SKEL);
2072:                                    }
2073:                                    // if the original class is assigned a new name by a script file
2074:                                    // mapping entry mark the remote class
2075:                                    if (originalClass.isFromScript()) {
2076:                                        classItem.setFromScript();
2077:                                    }
2078:                                    if (originalClass.isFromScriptMap()) {
2079:                                        classItem.setFromScriptMap();
2080:                                    }
2081:                                } else {
2082:                                    logger.log(Log.VERBOSE, "Cannot rename "
2083:                                            + className);
2084:                                    logger.log(Log.VERBOSE,
2085:                                            "(base class not found)");
2086:                                }
2087:                            }
2088:                        }
2089:                    }
2090:                } else {
2091:                    logger.log(Log.VERBOSE,
2092:                            "Skipping processing remote classes");
2093:                }
2094:            }
2095:
2096:            /** Retain all available package, class, method and field mappings thar are
2097:             * specified in the given vector.
2098:             * @param mappings vector that holds the mapping entries
2099:             * @throws MalformedPatternException If the compiled expression does not
2100:             * conform to the grammar understood by the PatternCompiler or if some other
2101:             * error in the expression is encountered.
2102:             */
2103:            public void retainMappings(Vector mappings)
2104:                    throws MalformedPatternException {
2105:                logger.log(Log.INFO, "Retaining all available mappings...");
2106:
2107:                Iterator iter = mappings.iterator();
2108:                while (iter.hasNext()) {
2109:                    ScriptEntry entry = (ScriptEntry) iter.next();
2110:
2111:                    switch (entry.getType()) {
2112:                    case ScriptConstants.TYPE_PACKAGE:
2113:                    case ScriptConstants.TYPE_PACKAGE_MAP:
2114:                        retainPackageMapping(entry);
2115:                        break;
2116:
2117:                    case ScriptConstants.TYPE_CLASS:
2118:                    case ScriptConstants.TYPE_CLASS_MAP:
2119:                        retainClassMapping(entry);
2120:                        break;
2121:
2122:                    case ScriptConstants.TYPE_METHOD:
2123:                    case ScriptConstants.TYPE_METHOD_MAP:
2124:                        retainMethodMapping(entry);
2125:                        break;
2126:
2127:                    case ScriptConstants.TYPE_FIELD:
2128:                    case ScriptConstants.TYPE_FIELD_MAP:
2129:                        retainFieldMapping(entry);
2130:                        break;
2131:
2132:                    default:
2133:                        // should never happen because we've already parsed the script
2134:                        // and created the vector correctly
2135:                        throw new IllegalArgumentException(
2136:                                "Illegal type in script file");
2137:                    }
2138:                }
2139:            }
2140:
2141:            /** Retain the given package mapping entry.
2142:             * @param entry a package mapping entry; may not be null
2143:             * @throws MalformedPatternException If the compiled expression does not
2144:             * conform to the grammar understood by the PatternCompiler or if some other
2145:             * error in the expression is encountered.
2146:             */
2147:            private void retainPackageMapping(ScriptEntry entry)
2148:                    throws MalformedPatternException {
2149:                Pattern pattern = compileRegex(entry.getName());
2150:                Iterator packages = findPackages(pattern);
2151:                // process all packages found
2152:                while (packages.hasNext()) {
2153:                    Pk pk = (Pk) packages.next();
2154:                    // only process the package if it wasn't processed earlier
2155:                    if (pk.isScriptEntryMatch() || pk.canForceObfuscate()
2156:                            || pk.canIgnoreElement())
2157:                        continue;
2158:                    pk.setScriptEntryMatch(true);
2159:
2160:                    // set the output name if one is specified
2161:                    if (ScriptConstants.TYPE_PACKAGE_MAP == entry.getType()) {
2162:                        retainItemMap(pk, entry.getMappedName());
2163:                    }
2164:                }
2165:            }
2166:
2167:            /** Retain the given class mapping entry.
2168:             * @param entry a class mapping entry; may not be null
2169:             * @throws MalformedPatternException If the compiled expression does not
2170:             * conform to the grammar understood by the PatternCompiler or if some other
2171:             * error in the expression is encountered.
2172:             */
2173:            private void retainClassMapping(ScriptEntry entry)
2174:                    throws MalformedPatternException {
2175:                Pattern pattern = compileRegex(entry.getName());
2176:                // for each available class mapping find all classes that match the
2177:                // search pattern
2178:                Iterator classes = findClasses(pattern);
2179:                while (classes.hasNext()) {
2180:                    // process all classes that match the search pattern
2181:                    Cl cl = (Cl) classes.next();
2182:                    // only process the class if it wasn't processed earlier
2183:                    if (cl.isScriptEntryMatch() || cl.canForceObfuscate()
2184:                            || cl.canIgnoreElement())
2185:                        continue;
2186:                    cl.setScriptEntryMatch(true);
2187:
2188:                    // if the "protected" modifier is given automatically assume "public"
2189:                    if (entry.canRetainProtected()) {
2190:                        entry.setRetainPublic(true);
2191:                    }
2192:
2193:                    switch (entry.getType()) {
2194:                    case ScriptConstants.TYPE_CLASS:
2195:                        // the entry specifies a ".class" directive
2196:                        // -> retain the class name
2197:                        retainItem(cl);
2198:                        // if a class should preserve its name also preserve the names of
2199:                        // all super elements in the tree
2200:                        retainHierarchy(cl.getParent());
2201:                        break;
2202:
2203:                    case ScriptConstants.TYPE_CLASS_MAP:
2204:                        // the entry specifies a ".class_map" directive
2205:                        // -> set the output name
2206:                        retainItemMap(cl, entry.getMappedName());
2207:                        // if a class should preserve its name also preserve the names of
2208:                        // all super elements in the tree
2209:                        retainHierarchy(cl.getParent());
2210:                        break;
2211:
2212:                    default:
2213:                        // should never happen
2214:                        throw new InternalError("Illegal class type mapping!");
2215:                    }
2216:                    // process the additional class options
2217:
2218:                    // if no "public" or "protected" modifier is given check whether
2219:                    // fields or methods should be retained
2220:                    if (!entry.canRetainPublic() && !entry.canRetainProtected()) {
2221:                        // if the "field" or "method" option is given mark all of them as
2222:                        // being visible
2223:                        if (entry.canRetainMethods()) {
2224:                            retainItems(cl.getMethodIterator());
2225:                        }
2226:                        if (entry.canRetainFields()) {
2227:                            retainItems(cl.getFieldIterator());
2228:                        }
2229:                    } else {
2230:                        // at least one of the "public" and "protected" modifiers is given
2231:                        Vector vec = new Vector();
2232:                        // check whether we should retain methods
2233:                        if (entry.canRetainMethods()
2234:                                || !entry.canRetainFields()) {
2235:                            Iterator mdIter = cl.getMethodIterator();
2236:                            while (mdIter.hasNext()) {
2237:                                Md md = (Md) mdIter.next();
2238:                                // check whether we should retain public or protected methods
2239:                                if ((entry.canRetainPublic() && Modifier
2240:                                        .isPublic(md.getModifiers()))
2241:                                        || (entry.canRetainProtected() && Modifier
2242:                                                .isProtected(md.getModifiers()))) {
2243:                                    vec.addElement(md);
2244:                                }
2245:                            }
2246:                        }
2247:                        // check whether we should retain fields
2248:                        if (entry.canRetainFields()
2249:                                || !entry.canRetainMethods()) {
2250:                            Iterator fdIter = cl.getFieldIterator();
2251:                            while (fdIter.hasNext()) {
2252:                                Fd fd = (Fd) fdIter.next();
2253:                                if ((entry.canRetainPublic() && Modifier
2254:                                        .isPublic(fd.getModifiers()))
2255:                                        || (entry.canRetainProtected() && Modifier
2256:                                                .isProtected(fd.getModifiers()))) {
2257:                                    vec.addElement(fd);
2258:                                }
2259:                            }
2260:                        }
2261:                        // retain all filtered out elements
2262:                        retainItems(vec.iterator());
2263:                    }
2264:                }
2265:            }
2266:
2267:            /** Retain the given method mapping entry.
2268:             * @param entry a method mapping entry; may not be null
2269:             * @throws MalformedPatternException If the compiled expression does not
2270:             * conform to the grammar understood by the PatternCompiler or if some other
2271:             * error in the expression is encountered.
2272:             */
2273:            private void retainMethodMapping(ScriptEntry entry)
2274:                    throws MalformedPatternException {
2275:                Pattern pattern = compileRegex(entry.getName());
2276:                // find all methods that match the search pattern and the optional
2277:                // descriptor specified in the entry
2278:                Iterator methods = findMethods(pattern, entry.getDescriptor());
2279:                // process all method mapping entries found
2280:                while (methods.hasNext()) {
2281:                    Md md = (Md) methods.next();
2282:                    // only process the method if it wasn't processed earlier
2283:                    if (md.isScriptEntryMatch() || md.canForceObfuscate()
2284:                            || md.canIgnoreElement())
2285:                        continue;
2286:                    md.setScriptEntryMatch(true);
2287:
2288:                    // only continue if the descriptor (if available) matches
2289:                    switch (entry.getType()) {
2290:                    case ScriptConstants.TYPE_METHOD:
2291:                        // the entry specifies a ".method" directive
2292:                        // -> retain the method name
2293:                        retainItem(md);
2294:                        break;
2295:
2296:                    case ScriptConstants.TYPE_METHOD_MAP:
2297:                        // the entry specifies a ".method_map" directive
2298:                        // -> set the output name
2299:                        retainItemMap(md, entry.getMappedName());
2300:                        break;
2301:
2302:                    default:
2303:                        // should never happen
2304:                        throw new InternalError("Illegal method type mapping!");
2305:                    }
2306:                }
2307:            }
2308:
2309:            /** Retain the given field mapping entry.
2310:             * @param entry a field mapping entry; may not be null
2311:             * @throws MalformedPatternException If the compiled expression does not
2312:             * conform to the grammar understood by the PatternCompiler or if some other
2313:             * error in the expression is encountered.
2314:             */
2315:            private void retainFieldMapping(ScriptEntry entry)
2316:                    throws MalformedPatternException {
2317:                Pattern pattern = compileRegex(entry.getName());
2318:                // find all fields that match the search pattern and the optional
2319:                // descriptor specified in the entry
2320:                Iterator fields = findMethods(pattern, entry.getDescriptor());
2321:                // process all field mapping entries found
2322:                while (fields.hasNext()) {
2323:                    Fd fd = (Fd) fields.next();
2324:                    // only process the field if it wasn't processed earlier
2325:                    if (fd.isScriptEntryMatch() || fd.canForceObfuscate()
2326:                            || fd.canIgnoreElement())
2327:                        continue;
2328:                    fd.setScriptEntryMatch(true);
2329:
2330:                    // only continue if the descriptor (if available) matches
2331:                    switch (entry.getType()) {
2332:                    case ScriptConstants.TYPE_FIELD:
2333:                        // the entry specifies a ".field" directive
2334:                        // -> retain the field name
2335:                        retainItem(fd);
2336:                        break;
2337:
2338:                    case ScriptConstants.TYPE_FIELD_MAP:
2339:                        // the entry specifies a ".field_map" directive
2340:                        // -> set the output name
2341:                        retainItemMap(fd, entry.getMappedName());
2342:                        break;
2343:
2344:                    default:
2345:                        // should never happen
2346:                        throw new InternalError("Illegal field type mapping!");
2347:                    }
2348:                }
2349:            }
2350:
2351:            /** Prevent the names of classes that are used in hardcoded references from
2352:             * being obfuscated.
2353:             */
2354:            public void retainHardcodedReferences() {
2355:                // if we should prevent hardcoded class names from being obfuscated
2356:                // retain their names
2357:                if (canAutoCorrectClassNames()) {
2358:                    logger.log(Log.VERBOSE,
2359:                            "Retaining hardcoded class names...");
2360:                    Iterator iter = hardcodedReferences.iterator();
2361:                    while (iter.hasNext()) {
2362:                        String str = (String) iter.next();
2363:                        if (null != str) {
2364:                            // replace all "." in the name by the separator char "/" used in the
2365:                            // internal class database
2366:                            TreeItem ti = findClass(str);
2367:                            if (null == ti) {
2368:                                logger.log("# Warning: cannot find class "
2369:                                        + str);
2370:                            } else {
2371:                                logger.log(Log.DEBUG, "# retaining class "
2372:                                        + ti.getFullInName());
2373:                            }
2374:                            retainHierarchy(ti);
2375:                        }
2376:                    }
2377:                } else {
2378:                    logger.log(Log.VERBOSE,
2379:                            "Skipping retaining hardcoded class names");
2380:                }
2381:            }
2382:
2383:            /** Prevent the names of serializable fields and methods from being
2384:             * obfuscated.
2385:             * @see #addSerializableMethod
2386:             * @see #addSerializableField
2387:             */
2388:            public void retainSerializableElements() {
2389:                int i;
2390:                // add all serializable fields
2391:                logger.log(Log.VERBOSE,
2392:                        "Processing possible serializable fields...");
2393:                logger.log(Log.DEBUG, "Number of fields available: "
2394:                        + serializableFields.size());
2395:                int sfieldsRetained = 0;
2396:                for (i = 0; i < serializableFields.size(); i++) {
2397:                    Fd fd = (Fd) serializableFields.elementAt(i);
2398:                    if (isSerializableClass((Cl) fd.getParent())) {
2399:                        retainItem(fd);
2400:                        sfieldsRetained++;
2401:                    }
2402:                }
2403:                logger.log(Log.DEBUG, "Number of fields retained: "
2404:                        + sfieldsRetained);
2405:
2406:                // add all additional methods
2407:                logger.log(Log.VERBOSE,
2408:                        "Processing possible serializable methods...");
2409:                logger.log(Log.DEBUG, "Number of methods available: "
2410:                        + serializableMethods.size());
2411:                int smethodsRetained = 0;
2412:                for (i = 0; i < serializableMethods.size(); i++) {
2413:                    Md md = (Md) serializableMethods.elementAt(i);
2414:                    if (isSerializableClass((Cl) md.getParent())) {
2415:                        retainItem(md);
2416:                        smethodsRetained++;
2417:                    }
2418:                }
2419:                logger.log(Log.DEBUG, "Number of methods retained: "
2420:                        + smethodsRetained);
2421:            }
2422:
2423:            /** Adds a method item which could be a serializable method item inside the
2424:             * tree to the list of methods that may not be obfuscated.
2425:             * @param md method item in the tree
2426:             */
2427:            public void addSerializableMethod(Md md) {
2428:                serializableMethods.add(md);
2429:            }
2430:
2431:            /** Adds a field item which could be a serializable field item inside the tree
2432:             * to the list of fields that may not be obfuscated.
2433:             * @param fd field item in the tree
2434:             */
2435:            public void addSerializableField(Fd fd) {
2436:                serializableFields.add(fd);
2437:            }
2438:
2439:            /** Checks whether the given class or one of its super classes implement the
2440:             * java.io.Serializable interface.
2441:             * @param cl the class to verify
2442:             * @return true if the class implements java.io.Serializable; false else
2443:             */
2444:            private boolean isSerializableClass(Cl cl) {
2445:                if (null == cl)
2446:                    return false;
2447:                if (cl.isSerializable())
2448:                    return true;
2449:
2450:                // check the implemented interfaces
2451:                String[] interfaces = cl.getSuperInterfaces();
2452:                boolean result = false;
2453:                int i = 0;
2454:                while (i < interfaces.length) {
2455:                    // check whether the current interface name is java.io.Serializable
2456:                    if (interfaces[i].equals(SERIALIZABLE_INTERFACE)) {
2457:                        // yes -> mark the class as being serializable
2458:                        result = true;
2459:                        break;
2460:                    }
2461:                    // check whether the referenced interface exists in the tree
2462:                    Cl interfaceCl = getCl(interfaces[i]);
2463:                    if (null != interfaceCl) {
2464:                        // the interface exists in the tree -> check whether it is serializable
2465:                        if (isSerializableClass(interfaceCl)) {
2466:                            // yes -> mark the class as being serializable
2467:                            result = true;
2468:                            break;
2469:                        }
2470:                    } else {
2471:                        // the class doesn't exist in the tree
2472:                        // -> check whether the class is accessible via the JVM
2473:                        if (isSerializableClass(interfaces[i])) {
2474:                            // the JVM-accessible class is serializable -> mark the current class
2475:                            result = true;
2476:                            break;
2477:                        }
2478:                    }
2479:                    i++;
2480:                }
2481:                // If we don't have a result so far check whether the super class is
2482:                // serializable
2483:                if (!result) {
2484:                    Cl super Cl = getCl(cl.getSuperclass());
2485:                    if (null == super Cl) {
2486:                        // the super class doesn't exist in the tree -> query the JVM
2487:                        result = isSerializableClass(cl.getSuperclass());
2488:                    } else {
2489:                        // otherwise query the internal name database
2490:                        result = isSerializableClass(super Cl);
2491:                    }
2492:                }
2493:                if (true == result) {
2494:                    cl.setSerializable(true);
2495:                }
2496:                return result;
2497:            }
2498:
2499:            /** Checks whether the given class or one of its super classes implement the
2500:             * java.io.Serializable interface.
2501:             * @param name the name of the class to verify
2502:             * @return true if the class implements java.io.Serializable; false else
2503:             */
2504:            private boolean isSerializableClass(String name) {
2505:                // try to receive a Class object from the running JVM
2506:                try {
2507:                    Class cls = Class.forName(name.replace('/', '.'), false,
2508:                            getClass().getClassLoader());
2509:                    return isSerializableClass(cls);
2510:                } catch (ClassNotFoundException cnfex) {
2511:                    // if the referenced class doesn't exist we don't care so far
2512:                }
2513:                return false;
2514:            }
2515:
2516:            /** Checks whether the given class or one of its super classes implement the
2517:             * java.io.Serializable interface.
2518:             * @param cls the class to verify
2519:             * @return true if the class implements java.io.Serializable; false else
2520:             */
2521:            private boolean isSerializableClass(Class cls) {
2522:                if (null == cls) {
2523:                    return false;
2524:                }
2525:
2526:                if (cls.isInterface()
2527:                        && cls.getName().equals(SERIALIZABLE_INTERFACE_CLASS)) {
2528:                    return true;
2529:                }
2530:                // check whether the super class implements java.io.Serializable
2531:                if (isSerializableClass(cls.getSuperclass())) {
2532:                    return true;
2533:                }
2534:                // check the implemented interfaces
2535:                Class[] interfaces = cls.getInterfaces();
2536:                for (int i = 0; i < interfaces.length; i++) {
2537:                    if (isSerializableClass(interfaces[i])) {
2538:                        return true;
2539:                    }
2540:                }
2541:                return false;
2542:            }
2543:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.