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 }
439 else if (_visitLists && (target instanceof List)) {
440 _scanCollection((List<Object>)target);
441 }
442 else if (_visitMaps && (target instanceof Map)) {
443 _scanMap((Map<Object, Object>)target);
444 }
445 else if (_visitSets && (target instanceof Set)) {
446 _scanCollection((Set<Object>)target);
447 }
448 else if (_visitCollections && (target instanceof Collection)) {
449 _scanCollection((Collection<Object>)target);
450 }
451 else {
452 _scanObject(target);
453 }
454 }
455
456 private void _scanCollection(Collection<Object> collection)
457 throws Exception {
458
459 for (Object element : collection) {
460 if (!_scanning) {
461 break;
462 }
463
464 _scan(element);
465 }
466 }
467
468 private void _scanMap(Map<Object, Object> map) throws Exception {
469 Set<Map.Entry<Object, Object>> entrySet = map.entrySet();
470
471 for (Map.Entry<Object, Object> entry : entrySet) {
472 if (!_scanning) {
473 break;
474 }
475
476 Object key = entry.getKey();
477 Object value = entry.getValue();
478
479 String name = null;
480
481 if (key != null) {
482 name = key.toString();
483 }
484
485 if (_isAcceptName(name)) {
486 _matchName(value, name);
487 _scan(value);
488 }
489 }
490 }
491
492 private void _scanObject(Object target) throws Exception {
493 Class<?> targetClass = target.getClass();
494
495 if (!_isAcceptClass(targetClass)) {
496 return;
497 }
498
499 while (targetClass != null) {
500 Field[] fields = targetClass.getDeclaredFields();
501
502 for (Field field : fields) {
503 if (!_scanning) {
504 break;
505 }
506
507 if (!_visitStaticFields) {
508 if ((field.getModifiers() & Modifier.STATIC) != 0) {
509 continue;
510 }
511 }
512
513 String fieldName = field.getName();
514
515 if (_isAcceptName(fieldName)) {
516 _matchField(target, field, fieldName);
517
518 field.setAccessible(true);
519
520 Object fieldValue = field.get(target);
521
522 if (fieldValue != null) {
523 _scan(fieldValue);
524 }
525 }
526 }
527
528 targetClass = targetClass.getSuperclass();
529 }
530 }
531
532 private static Log _log = LogFactoryUtil.getLog(
533 DeepNamedValueScanner.class);
534
535 private long _elapsedTime;
536 private String[] _excludedClassNames;
537 private String[] _excludedNames;
538 private String[] _includedClassNames;
539 private Object _matchedValue;
540 private int _matchingCount;
541 private Map<String, Dataset> _nameDatasets;
542 private boolean _scanning;
543 private int _skipFirstCount;
544 private boolean _trackUsageCount;
545 private Map<String, Dataset> _typeDatasets;
546 private final String _value;
547 private boolean _visitArrays;
548 private boolean _visitCollections;
549 private Set<String> _visitedIds;
550 private boolean _visitLists;
551 private boolean _visitMaps;
552 private boolean _visitSets;
553 private boolean _visitStaticFields;
554
555 private class Dataset
556 extends ObjectValuePair<String, IntegerWrapper>
557 implements Comparable<Dataset> {
558
559 @Override
560 public int compareTo(Dataset dataset) {
561 IntegerWrapper integerWrapper = dataset.getValue();
562
563 return integerWrapper.compareTo(getValue());
564 }
565
566 }
567
568 }