| /* |
| * Licensed to the Apache Software Foundation (ASF) under one or more |
| * contributor license agreements. See the NOTICE file distributed with |
| * this work for additional information regarding copyright ownership. |
| * The ASF licenses this file to You under the Apache License, Version 2.0 |
| * (the "License"); you may not use this file except in compliance with |
| * the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| package org.apache.ignite.codegen; |
| |
| import java.io.File; |
| import java.io.FileWriter; |
| import java.io.IOException; |
| import java.lang.reflect.Method; |
| import java.lang.reflect.Modifier; |
| import java.util.ArrayList; |
| import java.util.Arrays; |
| import java.util.Collection; |
| import java.util.Collections; |
| import java.util.Comparator; |
| import java.util.HashSet; |
| import java.util.List; |
| import java.util.Set; |
| import java.util.TreeSet; |
| import java.util.function.ObjIntConsumer; |
| import org.apache.ignite.internal.managers.systemview.SystemViewMBean; |
| import org.apache.ignite.internal.managers.systemview.walker.Filtrable; |
| import org.apache.ignite.internal.managers.systemview.walker.Order; |
| import org.apache.ignite.internal.processors.query.stat.view.StatisticsColumnConfigurationView; |
| import org.apache.ignite.internal.processors.query.stat.view.StatisticsColumnGlobalDataView; |
| import org.apache.ignite.internal.processors.query.stat.view.StatisticsColumnLocalDataView; |
| import org.apache.ignite.internal.processors.query.stat.view.StatisticsColumnPartitionDataView; |
| import org.apache.ignite.internal.util.typedef.F; |
| import org.apache.ignite.spi.systemview.view.BaselineNodeAttributeView; |
| import org.apache.ignite.spi.systemview.view.BaselineNodeView; |
| import org.apache.ignite.spi.systemview.view.BinaryMetadataView; |
| import org.apache.ignite.spi.systemview.view.CacheGroupIoView; |
| import org.apache.ignite.spi.systemview.view.CacheGroupView; |
| import org.apache.ignite.spi.systemview.view.CachePagesListView; |
| import org.apache.ignite.spi.systemview.view.CacheView; |
| import org.apache.ignite.spi.systemview.view.ClientConnectionAttributeView; |
| import org.apache.ignite.spi.systemview.view.ClientConnectionView; |
| import org.apache.ignite.spi.systemview.view.ClusterNodeView; |
| import org.apache.ignite.spi.systemview.view.ComputeJobView; |
| import org.apache.ignite.spi.systemview.view.ComputeTaskView; |
| import org.apache.ignite.spi.systemview.view.ConfigurationView; |
| import org.apache.ignite.spi.systemview.view.ContinuousQueryView; |
| import org.apache.ignite.spi.systemview.view.MetastorageView; |
| import org.apache.ignite.spi.systemview.view.MetricsView; |
| import org.apache.ignite.spi.systemview.view.NodeAttributeView; |
| import org.apache.ignite.spi.systemview.view.NodeMetricsView; |
| import org.apache.ignite.spi.systemview.view.PagesListView; |
| import org.apache.ignite.spi.systemview.view.PagesTimestampHistogramView; |
| import org.apache.ignite.spi.systemview.view.PartitionStateView; |
| import org.apache.ignite.spi.systemview.view.ScanQueryView; |
| import org.apache.ignite.spi.systemview.view.ServiceView; |
| import org.apache.ignite.spi.systemview.view.SnapshotView; |
| import org.apache.ignite.spi.systemview.view.SqlQueryHistoryView; |
| import org.apache.ignite.spi.systemview.view.SqlQueryView; |
| import org.apache.ignite.spi.systemview.view.StripedExecutorTaskView; |
| import org.apache.ignite.spi.systemview.view.SystemView; |
| import org.apache.ignite.spi.systemview.view.SystemViewRowAttributeWalker; |
| import org.apache.ignite.spi.systemview.view.TransactionView; |
| import org.apache.ignite.spi.systemview.view.datastructures.AtomicLongView; |
| import org.apache.ignite.spi.systemview.view.datastructures.AtomicReferenceView; |
| import org.apache.ignite.spi.systemview.view.datastructures.AtomicSequenceView; |
| import org.apache.ignite.spi.systemview.view.datastructures.AtomicStampedView; |
| import org.apache.ignite.spi.systemview.view.datastructures.CountDownLatchView; |
| import org.apache.ignite.spi.systemview.view.datastructures.QueueView; |
| import org.apache.ignite.spi.systemview.view.datastructures.ReentrantLockView; |
| import org.apache.ignite.spi.systemview.view.datastructures.SemaphoreView; |
| import org.apache.ignite.spi.systemview.view.datastructures.SetView; |
| import org.apache.ignite.spi.systemview.view.sql.SqlIndexView; |
| import org.apache.ignite.spi.systemview.view.sql.SqlSchemaView; |
| import org.apache.ignite.spi.systemview.view.sql.SqlTableColumnView; |
| import org.apache.ignite.spi.systemview.view.sql.SqlTableView; |
| import org.apache.ignite.spi.systemview.view.sql.SqlViewColumnView; |
| import org.apache.ignite.spi.systemview.view.sql.SqlViewView; |
| |
| import static org.apache.ignite.codegen.MessageCodeGenerator.DFLT_SRC_DIR; |
| |
| /** |
| * Application for code generation of {@link SystemViewRowAttributeWalker}. |
| * Usage: simply run main method from Ignite source folder(using IDE or other way). |
| * Generated code used in {@link SystemView}. |
| * |
| * @see SystemViewMBean |
| */ |
| public class SystemViewRowAttributeWalkerGenerator { |
| /** Methods that should be excluded from specific {@link SystemViewRowAttributeWalker}. */ |
| private static final Set<String> SYS_METHODS = new HashSet<>(Arrays.asList("equals", "hashCode", "toString", |
| "getClass")); |
| |
| /** Package for {@link SystemViewRowAttributeWalker} implementations. */ |
| public static final String WALKER_PACKAGE = "org.apache.ignite.internal.managers.systemview.walker"; |
| |
| /** */ |
| public static final String TAB = " "; |
| |
| /** |
| * @param args Command line arguments. |
| * @throws Exception If generation failed. |
| */ |
| public static void main(String[] args) throws Exception { |
| SystemViewRowAttributeWalkerGenerator gen = new SystemViewRowAttributeWalkerGenerator(); |
| |
| gen.generateAndWrite(CacheGroupView.class, DFLT_SRC_DIR); |
| gen.generateAndWrite(CacheView.class, DFLT_SRC_DIR); |
| gen.generateAndWrite(ServiceView.class, DFLT_SRC_DIR); |
| gen.generateAndWrite(ComputeTaskView.class, DFLT_SRC_DIR); |
| gen.generateAndWrite(ComputeJobView.class, DFLT_SRC_DIR); |
| gen.generateAndWrite(ClientConnectionView.class, DFLT_SRC_DIR); |
| gen.generateAndWrite(ClientConnectionAttributeView.class, DFLT_SRC_DIR); |
| gen.generateAndWrite(TransactionView.class, DFLT_SRC_DIR); |
| gen.generateAndWrite(ContinuousQueryView.class, DFLT_SRC_DIR); |
| gen.generateAndWrite(ClusterNodeView.class, DFLT_SRC_DIR); |
| gen.generateAndWrite(ScanQueryView.class, DFLT_SRC_DIR); |
| gen.generateAndWrite(SqlQueryView.class, DFLT_SRC_DIR); |
| gen.generateAndWrite(SqlQueryHistoryView.class, DFLT_SRC_DIR); |
| gen.generateAndWrite(StripedExecutorTaskView.class, DFLT_SRC_DIR); |
| gen.generateAndWrite(PagesListView.class, DFLT_SRC_DIR); |
| gen.generateAndWrite(CachePagesListView.class, DFLT_SRC_DIR); |
| gen.generateAndWrite(PartitionStateView.class, DFLT_SRC_DIR); |
| gen.generateAndWrite(BinaryMetadataView.class, DFLT_SRC_DIR); |
| gen.generateAndWrite(MetastorageView.class, DFLT_SRC_DIR); |
| gen.generateAndWrite(QueueView.class, DFLT_SRC_DIR); |
| gen.generateAndWrite(SetView.class, DFLT_SRC_DIR); |
| gen.generateAndWrite(AtomicLongView.class, DFLT_SRC_DIR); |
| gen.generateAndWrite(AtomicReferenceView.class, DFLT_SRC_DIR); |
| gen.generateAndWrite(AtomicSequenceView.class, DFLT_SRC_DIR); |
| gen.generateAndWrite(AtomicStampedView.class, DFLT_SRC_DIR); |
| gen.generateAndWrite(CountDownLatchView.class, DFLT_SRC_DIR); |
| gen.generateAndWrite(ReentrantLockView.class, DFLT_SRC_DIR); |
| gen.generateAndWrite(SemaphoreView.class, DFLT_SRC_DIR); |
| gen.generateAndWrite(BaselineNodeAttributeView.class, DFLT_SRC_DIR); |
| gen.generateAndWrite(BaselineNodeView.class, DFLT_SRC_DIR); |
| gen.generateAndWrite(NodeAttributeView.class, DFLT_SRC_DIR); |
| gen.generateAndWrite(NodeMetricsView.class, DFLT_SRC_DIR); |
| gen.generateAndWrite(CacheGroupIoView.class, DFLT_SRC_DIR); |
| gen.generateAndWrite(SnapshotView.class, DFLT_SRC_DIR); |
| gen.generateAndWrite(MetricsView.class, DFLT_SRC_DIR); |
| gen.generateAndWrite(PagesTimestampHistogramView.class, DFLT_SRC_DIR); |
| gen.generateAndWrite(ConfigurationView.class, DFLT_SRC_DIR); |
| |
| gen.generateAndWrite(SqlSchemaView.class, DFLT_SRC_DIR); |
| gen.generateAndWrite(SqlTableView.class, DFLT_SRC_DIR); |
| gen.generateAndWrite(SqlViewView.class, DFLT_SRC_DIR); |
| gen.generateAndWrite(SqlIndexView.class, DFLT_SRC_DIR); |
| gen.generateAndWrite(SqlTableColumnView.class, DFLT_SRC_DIR); |
| gen.generateAndWrite(SqlViewColumnView.class, DFLT_SRC_DIR); |
| |
| gen.generateAndWrite(StatisticsColumnConfigurationView.class, DFLT_SRC_DIR); |
| gen.generateAndWrite(StatisticsColumnLocalDataView.class, DFLT_SRC_DIR); |
| gen.generateAndWrite(StatisticsColumnGlobalDataView.class, DFLT_SRC_DIR); |
| gen.generateAndWrite(StatisticsColumnPartitionDataView.class, DFLT_SRC_DIR); |
| } |
| |
| /** |
| * Generates {@link SystemViewRowAttributeWalker} implementation and write it to the file. |
| * |
| * @param clazz Class to geneare {@link SystemViewRowAttributeWalker} for. |
| * @param srcRoot Source root folder. |
| * @param <T> type of the row. |
| * @throws IOException If generation failed. |
| */ |
| private <T> void generateAndWrite(Class<T> clazz, String srcRoot) throws IOException { |
| File walkerCls = new File(srcRoot + '/' + WALKER_PACKAGE.replaceAll("\\.", "/") + '/' + |
| clazz.getSimpleName() + "Walker.java"); |
| |
| Collection<String> code = generate(clazz); |
| |
| walkerCls.createNewFile(); |
| |
| try (FileWriter writer = new FileWriter(walkerCls)) { |
| for (String line : code) { |
| writer.write(line); |
| writer.write('\n'); |
| } |
| } |
| } |
| |
| /** |
| * Generates {@link SystemViewRowAttributeWalker} implementation. |
| * |
| * @param clazz Class to geneare {@link SystemViewRowAttributeWalker} for. |
| * @param <T> type of the row. |
| * @return Java source code of the {@link SystemViewRowAttributeWalker} implementation. |
| */ |
| private <T> Collection<String> generate(Class<T> clazz) { |
| final List<String> code = new ArrayList<>(); |
| final Set<String> imports = new TreeSet<>(Comparator.comparing(s -> s.replace(";", ""))); |
| |
| addImport(imports, SystemViewRowAttributeWalker.class); |
| addImport(imports, clazz); |
| |
| String simpleName = clazz.getSimpleName(); |
| |
| code.add("package " + WALKER_PACKAGE + ";"); |
| code.add(""); |
| code.add(""); |
| code.add("/**"); |
| code.add(" * Generated by {@code " + SystemViewRowAttributeWalkerGenerator.class.getName() + "}."); |
| code.add(" * {@link " + simpleName + "} attributes walker."); |
| code.add(" * "); |
| code.add(" * @see " + simpleName); |
| code.add(" */"); |
| code.add("public class " + simpleName + "Walker implements SystemViewRowAttributeWalker<" + simpleName + "> {"); |
| |
| List<String> filtrableAttrs = new ArrayList<>(); |
| |
| forEachMethod(clazz, (m, i) -> { |
| if (m.getAnnotation(Filtrable.class) != null) { |
| code.add(TAB + "/** Filter key for attribute \"" + m.getName() + "\" */"); |
| code.add(TAB + "public static final String " + m.getName() |
| .replaceAll("(\\p{Upper})", "_$1") |
| .toUpperCase() + "_FILTER = \"" + m.getName() + "\";"); |
| code.add(""); |
| |
| filtrableAttrs.add(m.getName()); |
| } |
| }); |
| |
| if (!filtrableAttrs.isEmpty()) { |
| addImport(imports, F.class); |
| addImport(imports, List.class); |
| addImport(imports, Collections.class); |
| |
| code.add(TAB + "/** List of filtrable attributes. */"); |
| code.add(TAB + "private static final List<String> FILTRABLE_ATTRS = Collections.unmodifiableList(F.asList("); |
| code.add(TAB + TAB + '\"' + String.join("\", \"", filtrableAttrs) + '\"'); |
| code.add(TAB + "));"); |
| code.add(""); |
| code.add(TAB + "/** {@inheritDoc} */"); |
| code.add(TAB + "@Override public List<String> filtrableAttributes() {"); |
| code.add(TAB + TAB + "return FILTRABLE_ATTRS;"); |
| code.add(TAB + "}"); |
| code.add(""); |
| } |
| |
| code.add(TAB + "/** {@inheritDoc} */"); |
| code.add(TAB + "@Override public void visitAll(AttributeVisitor v) {"); |
| |
| forEachMethod(clazz, (m, i) -> { |
| String name = m.getName(); |
| |
| Class<?> retClazz = m.getReturnType(); |
| |
| String line = TAB + TAB; |
| |
| if (!retClazz.isPrimitive() && !retClazz.getName().startsWith("java.lang")) |
| addImport(imports, retClazz); |
| |
| line += "v.accept(" + i + ", \"" + name + "\", " + retClazz.getSimpleName() + ".class);"; |
| |
| code.add(line); |
| }); |
| |
| code.add(TAB + "}"); |
| code.add(""); |
| code.add(TAB + "/** {@inheritDoc} */"); |
| code.add(TAB + "@Override public void visitAll(" + simpleName + " row, AttributeWithValueVisitor v) {"); |
| |
| forEachMethod(clazz, (m, i) -> { |
| String name = m.getName(); |
| |
| Class<?> retClazz = m.getReturnType(); |
| |
| String line = TAB + TAB; |
| |
| if (!retClazz.isPrimitive()) { |
| line += "v.accept(" + i + ", \"" + name + "\", " + retClazz.getSimpleName() + ".class, row." + m.getName() + "());"; |
| } |
| else if (retClazz == boolean.class) |
| line += "v.acceptBoolean(" + i + ", \"" + name + "\", row." + m.getName() + "());"; |
| else if (retClazz == char.class) |
| line += "v.acceptChar(" + i + ", \"" + name + "\", row." + m.getName() + "());"; |
| else if (retClazz == byte.class) |
| line += "v.acceptByte(" + i + ", \"" + name + "\", row." + m.getName() + "());"; |
| else if (retClazz == short.class) |
| line += "v.acceptShort(" + i + ", \"" + name + "\", row." + m.getName() + "());"; |
| else if (retClazz == int.class) |
| line += "v.acceptInt(" + i + ", \"" + name + "\", row." + m.getName() + "());"; |
| else if (retClazz == long.class) |
| line += "v.acceptLong(" + i + ", \"" + name + "\", row." + m.getName() + "());"; |
| else if (retClazz == float.class) |
| line += "v.acceptFloat(" + i + ", \"" + name + "\", row." + m.getName() + "());"; |
| else if (retClazz == double.class) |
| line += "v.acceptDouble(" + i + ", \"" + name + "\", row." + m.getName() + "());"; |
| |
| code.add(line); |
| }); |
| |
| code.add(TAB + "}"); |
| code.add(""); |
| |
| final int[] cnt = {0}; |
| forEachMethod(clazz, (m, i) -> cnt[0]++); |
| |
| code.add(TAB + "/** {@inheritDoc} */"); |
| code.add(TAB + "@Override public int count() {"); |
| code.add(TAB + TAB + "return " + cnt[0] + ';'); |
| code.add(TAB + "}"); |
| code.add("}"); |
| |
| code.addAll(2, imports); |
| |
| addLicenseHeader(code); |
| |
| return code; |
| } |
| |
| /** Adds import to set imports set. */ |
| private void addImport(Set<String> imports, Class<?> cls) { |
| imports.add("import " + cls.getName().replaceAll("\\$", ".") + ';'); |
| } |
| |
| /** |
| * Adds Apache License Header to the source code. |
| * |
| * @param code Source code. |
| */ |
| private void addLicenseHeader(List<String> code) { |
| List<String> lic = new ArrayList<>(); |
| |
| lic.add("/*"); |
| lic.add(" * Licensed to the Apache Software Foundation (ASF) under one or more"); |
| lic.add(" * contributor license agreements. See the NOTICE file distributed with"); |
| lic.add(" * this work for additional information regarding copyright ownership."); |
| lic.add(" * The ASF licenses this file to You under the Apache License, Version 2.0"); |
| lic.add(" * (the \"License\"); you may not use this file except in compliance with"); |
| lic.add(" * the License. You may obtain a copy of the License at"); |
| lic.add(" *"); |
| lic.add(" * http://www.apache.org/licenses/LICENSE-2.0"); |
| lic.add(" *"); |
| lic.add(" * Unless required by applicable law or agreed to in writing, software"); |
| lic.add(" * distributed under the License is distributed on an \"AS IS\" BASIS,"); |
| lic.add(" * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied."); |
| lic.add(" * See the License for the specific language governing permissions and"); |
| lic.add(" * limitations under the License."); |
| lic.add(" */"); |
| lic.add(""); |
| |
| code.addAll(0, lic); |
| } |
| |
| /** |
| * Iterates each method of the {@code clazz} and call consume {@code c} for it. |
| * |
| * @param c Method consumer. |
| */ |
| private void forEachMethod(Class<?> clazz, ObjIntConsumer<Method> c) { |
| Method[] methods = clazz.getMethods(); |
| |
| List<Method> notOrdered = new ArrayList<>(); |
| List<Method> ordered = new ArrayList<>(); |
| |
| for (int i = 0; i < methods.length; i++) { |
| Method m = methods[i]; |
| |
| if (Modifier.isStatic(m.getModifiers())) |
| continue; |
| |
| if (SYS_METHODS.contains(m.getName())) |
| continue; |
| |
| Class<?> retClazz = m.getReturnType(); |
| |
| if (retClazz == void.class) |
| continue; |
| |
| if (m.getAnnotation(Order.class) != null) |
| ordered.add(m); |
| else |
| notOrdered.add(m); |
| } |
| |
| Collections.sort(ordered, Comparator.comparingInt(m -> m.getAnnotation(Order.class).value())); |
| Collections.sort(notOrdered, Comparator.comparing(Method::getName)); |
| |
| for (int i = 0; i < ordered.size(); i++) |
| c.accept(ordered.get(i), i); |
| |
| for (int i = 0; i < notOrdered.size(); i++) |
| c.accept(notOrdered.get(i), i + ordered.size()); |
| } |
| } |