001
014
015 package com.liferay.portal.server;
016
017 import com.liferay.portal.kernel.log.Log;
018 import com.liferay.portal.kernel.log.LogFactoryUtil;
019 import com.liferay.portal.kernel.util.IntegerWrapper;
020 import com.liferay.portal.kernel.util.ObjectValuePair;
021 import com.liferay.portal.kernel.util.StringBundler;
022 import com.liferay.portal.kernel.util.StringUtil;
023
024 import java.lang.reflect.Field;
025 import java.lang.reflect.Modifier;
026 import java.lang.reflect.Proxy;
027
028 import java.util.ArrayList;
029 import java.util.Collection;
030 import java.util.Collections;
031 import java.util.HashMap;
032 import java.util.HashSet;
033 import java.util.List;
034 import java.util.Map;
035 import java.util.Set;
036
037
040 public class DeepNamedValueScanner {
041
042 public DeepNamedValueScanner(String value) {
043 _value = value.toLowerCase();
044 }
045
046 public DeepNamedValueScanner(String value, boolean visit) {
047 this(value);
048
049 _visitArrays = visit;
050 _visitCollections = visit;
051 _visitLists = visit;
052 _visitSets = visit;
053 _visitMaps = visit;
054 _visitStaticFields = visit;
055 }
056
057 public long getElapsedTime() {
058 return _elapsedTime;
059 }
060
061 public String[] getExcludedClassNames() {
062 return _excludedClassNames;
063 }
064
065 public String[] getExcludedNames() {
066 return _excludedNames;
067 }
068
069 public String[] getIncludedClassNames() {
070 return _includedClassNames;
071 }
072
073 public Object getMatchedValue() {
074 return _matchedValue;
075 }
076
077 public int getMatchingCount() {
078 return _matchingCount;
079 }
080
081 public int getSkipFirstCount() {
082 return _skipFirstCount;
083 }
084
085 public boolean isScanning() {
086 return _scanning;
087 }
088
089 public boolean isTrackUsageCount() {
090 return _trackUsageCount;
091 }
092
093 public boolean isVisitArrays() {
094 return _visitArrays;
095 }
096
097 public boolean isVisitCollectionss() {
098 return _visitCollections;
099 }
100
101 public boolean isVisitLists() {
102 return _visitLists;
103 }
104
105 public boolean isVisitMaps() {
106 return _visitMaps;
107 }
108
109 public boolean isVisitSets() {
110 return _visitSets;
111 }
112
113 public boolean isVisitStaticFields() {
114 return _visitStaticFields;
115 }
116
117 public void printStatistics(int topCount) {
118 if (!_trackUsageCount) {
119 return;
120 }
121
122 System.out.println("-- names statistics --");
123
124 _printStatistics(_nameDatasets.values(), topCount);
125
126 System.out.println("-- types statistics --");
127
128 _printStatistics(_typeDatasets.values(), topCount);
129 }
130
131 public boolean scan(Object target) throws Exception {
132 _elapsedTime = System.currentTimeMillis();
133
134 _visitedIds = new HashSet<String>();
135
136 _scanning = true;
137
138 _scan(target);
139
140 _visitedIds = null;
141
142 _elapsedTime = System.currentTimeMillis() - _elapsedTime;
143
144 if (_log.isDebugEnabled()) {
145 if (!_scanning) {
146 StringBundler sb = new StringBundler(5);
147
148 sb.append("Deep named value scanner found ");
149 sb.append(_matchingCount);
150 sb.append(" matches in ");
151 sb.append(_elapsedTime);
152 sb.append(" ms");
153
154 _log.debug(sb.toString());
155 }
156 else {
157 _log.debug("Deep named value scanner did not finish scanning");
158 }
159 }
160
161 return !_scanning;
162 }
163
164 public void setExcludedClassNames(String... excludedClassNames) {
165 _excludedClassNames = excludedClassNames;
166
167 StringUtil.lowerCase(excludedClassNames);
168 }
169
170 public void setExcludedNames(String... excludedNames) {
171 _excludedNames = excludedNames;
172
173 StringUtil.lowerCase(excludedNames);
174 }
175
176 public void setIncludedClassNames(String... includedClassNames) {
177 _includedClassNames = includedClassNames;
178
179 StringUtil.lowerCase(includedClassNames);
180 }
181
182 public void setSkipFirstCount(int skipFirstCount) {
183 _skipFirstCount = skipFirstCount;
184 }
185
186 public void setTrackUsageCount(boolean trackUsageCount) {
187 _trackUsageCount = trackUsageCount;
188
189 if (trackUsageCount) {
190 _nameDatasets = new HashMap<String, Dataset>();
191 _typeDatasets = new HashMap<String, Dataset>();
192 }
193 }
194
195 public void setVisitArrays(boolean visitArrays) {
196 _visitArrays = visitArrays;
197 }
198
199 public void setVisitCollections(boolean visitCollections) {
200 _visitCollections = visitCollections;
201 }
202
203 public void setVisitLists(boolean visitLists) {
204 _visitLists = visitLists;
205 }
206
207 public void setVisitMaps(boolean visitMaps) {
208 _visitMaps = visitMaps;
209 }
210
211 public void setVisitSets(boolean visitSets) {
212 _visitSets = visitSets;
213 }
214
215 public void setVisitStaticFields(boolean visitStaticFields) {
216 _visitStaticFields = visitStaticFields;
217 }
218
219 private void _incrementUsageCount(
220 Map<String, Dataset> datasets, String name) {
221
222 Dataset dataset = datasets.get(name);
223
224 if (dataset == null) {
225 dataset = new Dataset();
226
227 dataset.setKey(name);
228 dataset.setValue(new IntegerWrapper());
229
230 datasets.put(name, dataset);
231 }
232
233 IntegerWrapper integerWrapper = dataset.getValue();
234
235 integerWrapper.increment();
236 }
237
238 private boolean _isAcceptClass(Class<?> targetClass) {
239 String targetClassName = targetClass.getName();
240
241 targetClassName = targetClassName.toLowerCase();
242
243 if (targetClassName.startsWith("java.")) {
244 return false;
245 }
246
247 if (targetClassName.startsWith("sun.misc.")) {
248 return false;
249 }
250
251 if (targetClassName.contains("log")) {
252 return false;
253 }
254
255 if (_excludedClassNames != null) {
256 for (String excludedClassName : _excludedClassNames) {
257 if (targetClassName.contains(excludedClassName)) {
258
259 return false;
260 }
261 }
262 }
263
264 if (_includedClassNames != null) {
265 boolean accept = false;
266
267 for (String includedClassName : _includedClassNames) {
268
269 if (targetClassName.contains(includedClassName)) {
270 accept = true;
271
272 break;
273 }
274 }
275
276 if (!accept) {
277 return false;
278 }
279 }
280
281 if (_trackUsageCount) {
282 _incrementUsageCount(_typeDatasets, targetClass.getName());
283 }
284
285 return true;
286 }
287
288 private boolean _isAcceptName(String name) {
289 if (name == null) {
290 return true;
291 }
292
293 name = name.toLowerCase();
294
295 if (_excludedNames != null) {
296 for (String excludedNames : _excludedNames) {
297 if (name.contains(excludedNames)) {
298
299 return false;
300 }
301 }
302 }
303
304 if (_trackUsageCount) {
305 _incrementUsageCount(_nameDatasets, name);
306 }
307
308 return true;
309 }
310
311 private void _matchField(Object target, Field field, String name)
312 throws IllegalAccessException {
313
314 if (name == null) {
315 return;
316 }
317
318 _matchingCount++;
319
320 name = name.toLowerCase();
321
322 if (name.contains(_value)) {
323 if (_skipFirstCount > 0) {
324 _skipFirstCount--;
325
326 return;
327 }
328
329 field.setAccessible(true);
330
331 _matchedValue = field.get(target);
332
333 _scanning = false;
334 }
335 }
336
337 private void _matchName(Object value, String name) {
338 if (name == null) {
339 return;
340 }
341
342 _matchingCount++;
343
344 name = name.toLowerCase();
345
346 if (name.contains(_value)) {
347 if (_skipFirstCount > 0) {
348 _skipFirstCount--;
349
350 return;
351 }
352
353 _matchedValue = value;
354
355 _scanning = false;
356 }
357 }
358
359 private void _printStatistics(Collection<Dataset> datasets, int topCount) {
360 List<Dataset> datasetsList = new ArrayList<Dataset>();
361
362 for (Dataset dataset : datasets) {
363 datasetsList.add(dataset);
364 }
365
366 Collections.sort(datasetsList);
367
368 for (Dataset dataset : datasetsList) {
369 System.out.println(dataset.getValue() + " " + dataset.getKey());
370
371 topCount--;
372
373 if (topCount == 0) {
374 break;
375 }
376 }
377 }
378
379 private Object _resolveJavaProxy(Object target)
380 throws IllegalAccessException, NoSuchFieldException {
381
382 Class<?> targetClass = target.getClass();
383 Class<?> targetSuperClass = targetClass.getSuperclass();
384
385 if ((targetSuperClass != null) &&
386 targetSuperClass.equals(Proxy.class)) {
387
388 Field field = targetSuperClass.getDeclaredField("h");
389
390 field.setAccessible(true);
391
392 target = field.get(target);
393 }
394
395 return target;
396 }
397
398 private void _scan(Object target) throws Exception {
399 if (target == null) {
400 return;
401 }
402
403 if (!_scanning) {
404 return;
405 }
406
407 target = _resolveJavaProxy(target);
408
409 String visitedId = null;
410
411 try {
412 visitedId = String.valueOf(System.identityHashCode(target));
413
414 if (_visitedIds.contains(visitedId)) {
415 return;
416 }
417 }
418 catch (Exception e) {
419 return;
420 }
421
422 _visitedIds.add(visitedId);
423
424 Class<?> targetClass = target.getClass();
425
426 if (targetClass.isArray()) {
427 if (!_visitArrays) {
428 return;
429 }
430
431 Class<?> componentTypeClass = targetClass.getComponentType();
432
433 if (componentTypeClass.isPrimitive() == false) {
434 Object[] array = (Object[])target;
435
436 for (Object element : array) {
437 _scan(element);
438 }
439 }
440
441 }
442 else if (_visitLists && (target instanceof List)) {
443 _scanCollection((List<Object>)target);
444 }
445 else if (_visitMaps && (target instanceof Map)) {
446 _scanMap((Map<Object, Object>)target);
447 }
448 else if (_visitSets && (target instanceof Set)) {
449 _scanCollection((Set<Object>)target);
450 }
451 else if (_visitCollections && (target instanceof Collection)) {
452 _scanCollection((Collection<Object>)target);
453 }
454 else {
455 _scanObject(target);
456 }
457 }
458
459 private void _scanCollection(Collection<Object> collection)
460 throws Exception {
461
462 for (Object element : collection) {
463 if (!_scanning) {
464 break;
465 }
466
467 _scan(element);
468 }
469 }
470
471 private void _scanMap(Map<Object, Object> map) throws Exception {
472 Set<Map.Entry<Object, Object>> entrySet = map.entrySet();
473
474 for (Map.Entry<Object, Object> entry : entrySet) {
475 if (!_scanning) {
476 break;
477 }
478
479 Object key = entry.getKey();
480 Object value = entry.getValue();
481
482 String name = null;
483
484 if (key != null) {
485 name = key.toString();
486 }
487
488 if (_isAcceptName(name)) {
489 _matchName(value, name);
490 _scan(value);
491 }
492 }
493 }
494
495 private void _scanObject(Object target) throws Exception {
496 Class<?> targetClass = target.getClass();
497
498 if (!_isAcceptClass(targetClass)) {
499 return;
500 }
501
502 while (targetClass != null) {
503 Field[] fields = targetClass.getDeclaredFields();
504
505 for (Field field : fields) {
506 if (!_scanning) {
507 break;
508 }
509
510 if (!_visitStaticFields) {
511 if ((field.getModifiers() & Modifier.STATIC) != 0) {
512 continue;
513 }
514 }
515
516 String fieldName = field.getName();
517
518 if (_isAcceptName(fieldName)) {
519 _matchField(target, field, fieldName);
520
521 field.setAccessible(true);
522
523 Object fieldValue = field.get(target);
524
525 if (fieldValue != null) {
526 _scan(fieldValue);
527 }
528 }
529 }
530
531 targetClass = targetClass.getSuperclass();
532 }
533 }
534
535 private static Log _log = LogFactoryUtil.getLog(
536 DeepNamedValueScanner.class);
537
538 private long _elapsedTime;
539 private String[] _excludedClassNames;
540 private String[] _excludedNames;
541 private String[] _includedClassNames;
542 private Object _matchedValue;
543 private int _matchingCount;
544 private Map<String, Dataset> _nameDatasets;
545 private boolean _scanning;
546 private int _skipFirstCount;
547 private boolean _trackUsageCount;
548 private Map<String, Dataset> _typeDatasets;
549 private final String _value;
550 private boolean _visitArrays;
551 private boolean _visitCollections;
552 private Set<String> _visitedIds;
553 private boolean _visitLists;
554 private boolean _visitMaps;
555 private boolean _visitSets;
556 private boolean _visitStaticFields;
557
558 private class Dataset
559 extends ObjectValuePair<String, IntegerWrapper>
560 implements Comparable<Dataset> {
561
562 public int compareTo(Dataset dataset) {
563 IntegerWrapper integerWrapper = dataset.getValue();
564
565 return integerWrapper.compareTo(getValue());
566 }
567
568 }
569
570 }