1 /*
   2  * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
   3  *
   4  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   5  *
   6  * The contents of this file are subject to the terms of either the Universal Permissive License
   7  * v 1.0 as shown at http://oss.oracle.com/licenses/upl
   8  *
   9  * or the following license:
  10  *
  11  * Redistribution and use in source and binary forms, with or without modification, are permitted
  12  * provided that the following conditions are met:
  13  *
  14  * 1. Redistributions of source code must retain the above copyright notice, this list of conditions
  15  * and the following disclaimer.
  16  *
  17  * 2. Redistributions in binary form must reproduce the above copyright notice, this list of
  18  * conditions and the following disclaimer in the documentation and/or other materials provided with
  19  * the distribution.
  20  *
  21  * 3. Neither the name of the copyright holder nor the names of its contributors may be used to
  22  * endorse or promote products derived from this software without specific prior written permission.
  23  *
  24  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
  25  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
  26  * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
  27  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  28  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
  29  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
  30  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY
  31  * WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  32  */
  33 package org.openjdk.jmc.flightrecorder.rules.jdk.general;
  34 
  35 import java.text.MessageFormat;
  36 import java.util.ArrayList;
  37 import java.util.Collection;
  38 import java.util.Collections;
  39 import java.util.Set;
  40 import java.util.concurrent.Callable;
  41 import java.util.concurrent.FutureTask;
  42 import java.util.concurrent.RunnableFuture;
  43 
  44 import org.openjdk.jmc.common.item.Aggregators;
  45 import org.openjdk.jmc.common.item.IItemCollection;
  46 import org.openjdk.jmc.common.util.IPreferenceValueProvider;
  47 import org.openjdk.jmc.common.util.StringToolkit;
  48 import org.openjdk.jmc.common.util.TypedPreference;
  49 import org.openjdk.jmc.flightrecorder.jdk.JdkAttributes;
  50 import org.openjdk.jmc.flightrecorder.jdk.JdkFilters;
  51 import org.openjdk.jmc.flightrecorder.jdk.JdkQueries;
  52 import org.openjdk.jmc.flightrecorder.jdk.JdkTypeIDs;
  53 import org.openjdk.jmc.flightrecorder.rules.IRule;
  54 import org.openjdk.jmc.flightrecorder.rules.Result;
  55 import org.openjdk.jmc.flightrecorder.rules.jdk.dataproviders.JvmInternalsDataProvider;
  56 import org.openjdk.jmc.flightrecorder.rules.jdk.messages.internal.Messages;
  57 import org.openjdk.jmc.flightrecorder.rules.util.JfrRuleTopics;
  58 import org.openjdk.jmc.flightrecorder.rules.util.RulesToolkit;
  59 import org.openjdk.jmc.flightrecorder.rules.util.RulesToolkit.EventAvailability;
  60 import org.owasp.encoder.Encode;
  61 
  62 public class DuplicateFlagsRule implements IRule {
  63 
  64         private static final String RESULT_ID = "DuplicateFlags"; //$NON-NLS-1$
  65 
  66         private Result getResult(IItemCollection items, IPreferenceValueProvider vp) {
  67                 EventAvailability eventAvailability = RulesToolkit.getEventAvailability(items, JdkTypeIDs.VM_INFO);
  68                 if (eventAvailability != EventAvailability.AVAILABLE) {
  69                         return RulesToolkit.getEventAvailabilityResult(this, items, eventAvailability, JdkTypeIDs.VM_INFO);
  70                 }
  71 
  72                 IItemCollection jvmInfoItems = items.apply(JdkFilters.VM_INFO);
  73 
  74                 // FIXME: Should we check if there are different jvm args in different chunks?
  75                 Set<String> args = jvmInfoItems.getAggregate(Aggregators.distinct(JdkAttributes.JVM_ARGUMENTS));
  76                 if (args != null && !args.isEmpty()) {
  77                         
  78                         Collection<ArrayList<String>> dupes = JvmInternalsDataProvider.
  79                                         checkDuplicates(args.iterator().next());
  80 
  81                         if (!dupes.isEmpty()) {
  82                                 StringBuilder sb = new StringBuilder();
  83                                 sb.append("<ul>"); //$NON-NLS-1$
  84                                 for (ArrayList<String> dupe : dupes) {
  85                                         sb.append("<li>" + Encode.forHtml(StringToolkit.join(dupe, ", ")) + "</li>"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
  86                                 }
  87                                 sb.append("</ul>"); //$NON-NLS-1$
  88                                 String shortDescription = dupes.size() > 1
  89                                                 ? MessageFormat.format(Messages.getString(Messages.DuplicateFlagsRuleFactory_TEXT_WARN),
  90                                                                 dupes.size())
  91                                                 : Messages.getString(Messages.DuplicateFlagsRuleFactory_TEXT_WARN_SINGULAR);
  92                                 String longDescription = shortDescription + " " + MessageFormat //$NON-NLS-1$
  93                                                 .format(Messages.getString(Messages.DuplicateFlagsRuleFactory_TEXT_WARN_LONG), sb.toString());
  94                                 return new Result(this, 50, shortDescription, longDescription, JdkQueries.VM_INFO);
  95                         }
  96                 }
  97                 return new Result(this, 0, Messages.getString(Messages.DuplicateFlagsRuleFactory_TEXT_OK));
  98         }
  99 
 100         @Override
 101         public RunnableFuture<Result> evaluate(final IItemCollection items, final IPreferenceValueProvider valueProvider) {
 102                 FutureTask<Result> evaluationTask = new FutureTask<>(new Callable<Result>() {
 103                         @Override
 104                         public Result call() throws Exception {
 105                                 return getResult(items, valueProvider);
 106                         }
 107                 });
 108                 return evaluationTask;
 109         }
 110 
 111         @Override
 112         public Collection<TypedPreference<?>> getConfigurationAttributes() {
 113                 return Collections.emptyList();
 114         }
 115 
 116         @Override
 117         public String getId() {
 118                 return RESULT_ID;
 119         }
 120 
 121         @Override
 122         public String getName() {
 123                 return Messages.getString(Messages.DuplicateFlagsRuleFactory_RULE_NAME);
 124         }
 125 
 126         @Override
 127         public String getTopic() {
 128                 return JfrRuleTopics.JVM_INFORMATION_TOPIC;
 129         }
 130 }