001: /*
002:
003: Derby - Class org.apache.derby.iapi.services.classfile.ClassEnumeration
004:
005: Licensed to the Apache Software Foundation (ASF) under one or more
006: contributor license agreements. See the NOTICE file distributed with
007: this work for additional information regarding copyright ownership.
008: The ASF licenses this file to you under the Apache License, Version 2.0
009: (the "License"); you may not use this file except in compliance with
010: the License. You may obtain a copy of the License at
011:
012: http://www.apache.org/licenses/LICENSE-2.0
013:
014: Unless required by applicable law or agreed to in writing, software
015: distributed under the License is distributed on an "AS IS" BASIS,
016: WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
017: See the License for the specific language governing permissions and
018: limitations under the License.
019:
020: */
021:
022: package org.apache.derby.iapi.services.classfile;
023:
024: import java.util.Enumeration;
025: import java.util.HashSet;
026: import java.util.StringTokenizer;
027: import org.apache.derby.iapi.services.classfile.VMDescriptor;
028:
029: /**
030: An enumeration that filters only classes
031: from the enumeration of the class pool.
032:
033: Code has been added to also include classes referenced in method and
034: field signatures.
035: */
036:
037: class ClassEnumeration implements Enumeration {
038: ClassHolder cpt;
039: Enumeration inner;
040: CONSTANT_Index_info position;
041: HashSet foundClasses;
042: Enumeration classList;
043:
044: ClassEnumeration(ClassHolder cpt, Enumeration e,
045: Enumeration methods, Enumeration fields) {
046: this .cpt = cpt;
047: inner = e;
048: foundClasses = new HashSet(30, 0.8f);
049: findMethodReferences(methods, foundClasses);
050: findFieldReferences(fields, foundClasses);
051: findClassReferences(foundClasses);
052: classList = java.util.Collections.enumeration(foundClasses);
053:
054: }
055:
056: public boolean hasMoreElements() {
057: return classList.hasMoreElements();
058: }
059:
060: // uses cpt and inner
061: private void findClassReferences(HashSet foundClasses) {
062:
063: ConstantPoolEntry item;
064: CONSTANT_Index_info ref;
065:
066: while (inner.hasMoreElements()) {
067: item = (ConstantPoolEntry) inner.nextElement();
068: if (item == null)
069: continue;
070: if (item.getTag() == VMDescriptor.CONSTANT_Class) {
071: ref = (CONSTANT_Index_info) item;
072:
073: String className = cpt.className(ref.getIndex());
074:
075: // if this is an array type, distillClasses can
076: // handle it
077: if (className.startsWith("[")) {
078: distillClasses(className, foundClasses);
079: continue;
080: }
081:
082: // now we've got either a primitive type or a classname
083: // primitive types are all a single char
084:
085: if (className.length() > 1) {
086: //we've got a class
087: if (className.startsWith("java")) {
088: //skip it
089: continue;
090: }
091:
092: foundClasses.add(className);
093: }
094: }
095: }
096:
097: }
098:
099: private void findMethodReferences(Enumeration methods,
100: HashSet foundClasses) {
101: while (methods.hasMoreElements()) {
102: ClassMember member = (ClassMember) methods.nextElement();
103: String description = member.getDescriptor();
104: distillClasses(description, foundClasses);
105: }
106: }
107:
108: private void findFieldReferences(Enumeration fields,
109: HashSet foundClasses) {
110: while (fields.hasMoreElements()) {
111: ClassMember member = (ClassMember) fields.nextElement();
112: String description = member.getDescriptor();
113: distillClasses(description, foundClasses);
114: }
115: }
116:
117: void distillClasses(String fieldOrMethodSig, HashSet foundClasses) {
118: if (fieldOrMethodSig == null || fieldOrMethodSig.length() < 1) {
119: //empty string
120: return;
121: }
122:
123: if (fieldOrMethodSig.charAt(0) != '(') {
124: // first time through, we're dealing with a field here
125: // otherwise, it is a token from a method signature
126:
127: int classNameStart = fieldOrMethodSig.indexOf('L');
128:
129: if (classNameStart == -1) {
130: // no class in the type, so stop
131: return;
132: }
133:
134: // chop off any leading ['s or other Java-primitive type
135: // signifiers (like I or L) *AND* substitute the dots
136: String fieldType = fieldOrMethodSig.substring(
137: classNameStart + 1).replace('/', '.');
138:
139: // we have to check for the semi-colon in case we are
140: // actually looking at a token from a method signature
141: if (fieldType.endsWith(";")) {
142: fieldType = fieldType.substring(0,
143: fieldType.length() - 1);
144: }
145:
146: if (fieldType.startsWith("java")) {
147: return; // it's a java base class and we don't care about
148: // that either
149: }
150:
151: foundClasses.add(fieldType);
152: return;
153: } else {
154: // it's a method signature
155: StringTokenizer tokens = new StringTokenizer(
156: fieldOrMethodSig, "();[");
157: while (tokens.hasMoreElements()) {
158: String aToken = (String) tokens.nextToken();
159: // because of the semi-colon delimiter in the tokenizer, we
160: // can have only one class name per token and it must be the
161: // last item in the token
162: int classNameStart = aToken.indexOf('L');
163: if (classNameStart != -1) {
164: distillClasses(aToken, foundClasses);
165: } else {
166: continue;
167: }
168: }
169: }
170: }
171:
172: public Object nextElement() {
173: return classList.nextElement();
174: }
175:
176: }
|