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 return false;
259 }
260 }
261 }
262
263 if (_includedClassNames != null) {
264 boolean accept = false;
265
266 for (String includedClassName : _includedClassNames) {
267 if (targetClassName.contains(includedClassName)) {
268 accept = true;
269
270 break;
271 }
272 }
273
274 if (!accept) {
275 return false;
276 }
277 }
278
279 if (_trackUsageCount) {
280 _incrementUsageCount(_typeDatasets, targetClass.getName());
281 }
282
283 return true;
284 }
285
286 private boolean _isAcceptName(String name) {
287 if (name == null) {
288 return true;
289 }
290
291 name = name.toLowerCase();
292
293 if (_excludedNames != null) {
294 for (String excludedNames : _excludedNames) {
295 if (name.contains(excludedNames)) {
296 return false;
297 }
298 }
299 }
300
301 if (_trackUsageCount) {
302 _incrementUsageCount(_nameDatasets, name);
303 }
304
305 return true;
306 }
307
308 private void _matchField(Object target, Field field, String name)
309 throws IllegalAccessException {
310
311 if (name == null) {
312 return;
313 }
314
315 _matchingCount++;
316
317 name = name.toLowerCase();
318
319 if (name.contains(_value)) {
320 if (_skipFirstCount > 0) {
321 _skipFirstCount--;
322
323 return;
324 }
325
326 field.setAccessible(true);
327
328 _matchedValue = field.get(target);
329
330 _scanning = false;
331 }
332 }
333
334 private void _matchName(Object value, String name) {
335 if (name == null) {
336 return;
337 }
338
339 _matchingCount++;
340
341 name = name.toLowerCase();
342
343 if (name.contains(_value)) {
344 if (_skipFirstCount > 0) {
345 _skipFirstCount--;
346
347 return;
348 }
349
350 _matchedValue = value;
351
352 _scanning = false;
353 }
354 }
355
356 private void _printStatistics(Collection<Dataset> datasets, int topCount) {
357 List<Dataset> datasetsList = new ArrayList<Dataset>();
358
359 for (Dataset dataset : datasets) {
360 datasetsList.add(dataset);
361 }
362
363 Collections.sort(datasetsList);
364
365 for (Dataset dataset : datasetsList) {
366 System.out.println(dataset.getValue() + " " + dataset.getKey());
367
368 topCount--;
369
370 if (topCount == 0) {
371 break;
372 }
373 }
374 }
375
376 private Object _resolveJavaProxy(Object target)
377 throws IllegalAccessException, NoSuchFieldException {
378
379 Class<?> targetClass = target.getClass();
380 Class<?> targetSuperClass = targetClass.getSuperclass();
381
382 if ((targetSuperClass != null) &&
383 targetSuperClass.equals(Proxy.class)) {
384
385 Field field = targetSuperClass.getDeclaredField("h");
386
387 field.setAccessible(true);
388
389 target = field.get(target);
390 }
391
392 return target;
393 }
394
395 private void _scan(Object target) throws Exception {
396 if (target == null) {
397 return;
398 }
399
400 if (!_scanning) {
401 return;
402 }
403
404 target = _resolveJavaProxy(target);
405
406 String visitedId = null;
407
408 try {
409 visitedId = String.valueOf(System.identityHashCode(target));
410
411 if (_visitedIds.contains(visitedId)) {
412 return;
413 }
414 }
415 catch (Exception e) {
416 return;
417 }
418
419 _visitedIds.add(visitedId);
420
421 Class<?> targetClass = target.getClass();
422
423 if (targetClass.isArray()) {
424 if (!_visitArrays) {
425 return;
426 }
427
428 Class<?> componentTypeClass = targetClass.getComponentType();
429
430 if (componentTypeClass.isPrimitive() == false) {
431 Object[] array = (Object[])target;
432
433 for (Object element : array) {
434 _scan(element);
435 }
436 }
437 }
438 else if (_visitLists && (target instanceof List)) {
439 _scanCollection((List<Object>)target);
440 }
441 else if (_visitMaps && (target instanceof Map)) {
442 _scanMap((Map<Object, Object>)target);
443 }
444 else if (_visitSets && (target instanceof Set)) {
445 _scanCollection((Set<Object>)target);
446 }
447 else if (_visitCollections && (target instanceof Collection)) {
448 _scanCollection((Collection<Object>)target);
449 }
450 else {
451 _scanObject(target);
452 }
453 }
454
455 private void _scanCollection(Collection<Object> collection)
456 throws Exception {
457
458 for (Object element : collection) {
459 if (!_scanning) {
460 break;
461 }
462
463 _scan(element);
464 }
465 }
466
467 private void _scanMap(Map<Object, Object> map) throws Exception {
468 Set<Map.Entry<Object, Object>> entrySet = map.entrySet();
469
470 for (Map.Entry<Object, Object> entry : entrySet) {
471 if (!_scanning) {
472 break;
473 }
474
475 Object key = entry.getKey();
476 Object value = entry.getValue();
477
478 String name = null;
479
480 if (key != null) {
481 name = key.toString();
482 }
483
484 if (_isAcceptName(name)) {
485 _matchName(value, name);
486 _scan(value);
487 }
488 }
489 }
490
491 private void _scanObject(Object target) throws Exception {
492 Class<?> targetClass = target.getClass();
493
494 if (!_isAcceptClass(targetClass)) {
495 return;
496 }
497
498 while (targetClass != null) {
499 Field[] fields = targetClass.getDeclaredFields();
500
501 for (Field field : fields) {
502 if (!_scanning) {
503 break;
504 }
505
506 if (!_visitStaticFields) {
507 if ((field.getModifiers() & Modifier.STATIC) != 0) {
508 continue;
509 }
510 }
511
512 String fieldName = field.getName();
513
514 if (_isAcceptName(fieldName)) {
515 _matchField(target, field, fieldName);
516
517 field.setAccessible(true);
518
519 Object fieldValue = field.get(target);
520
521 if (fieldValue != null) {
522 _scan(fieldValue);
523 }
524 }
525 }
526
527 targetClass = targetClass.getSuperclass();
528 }
529 }
530
531 private static Log _log = LogFactoryUtil.getLog(
532 DeepNamedValueScanner.class);
533
534 private long _elapsedTime;
535 private String[] _excludedClassNames;
536 private String[] _excludedNames;
537 private String[] _includedClassNames;
538 private Object _matchedValue;
539 private int _matchingCount;
540 private Map<String, Dataset> _nameDatasets;
541 private boolean _scanning;
542 private int _skipFirstCount;
543 private boolean _trackUsageCount;
544 private Map<String, Dataset> _typeDatasets;
545 private final String _value;
546 private boolean _visitArrays;
547 private boolean _visitCollections;
548 private Set<String> _visitedIds;
549 private boolean _visitLists;
550 private boolean _visitMaps;
551 private boolean _visitSets;
552 private boolean _visitStaticFields;
553
554 private class Dataset
555 extends ObjectValuePair<String, IntegerWrapper>
556 implements Comparable<Dataset> {
557
558 @Override
559 public int compareTo(Dataset dataset) {
560 IntegerWrapper integerWrapper = dataset.getValue();
561
562 return integerWrapper.compareTo(getValue());
563 }
564
565 }
566
567 }