783ac4cac0137fc75397744b29f5305dff8e61d4
[policy/apex-pdp.git] /
1 /*-
2  * ============LICENSE_START=======================================================
3  *  Copyright (C) 2016-2018 Ericsson. All rights reserved.
4  *  Modifications Copyright (C) 2020 Nordix Foundation.
5  *  Modifications Copyright (C) 2021 Bell Canada. All rights reserved.
6  * ================================================================================
7  * Licensed under the Apache License, Version 2.0 (the "License");
8  * you may not use this file except in compliance with the License.
9  * You may obtain a copy of the License at
10  *
11  *      http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing, software
14  * distributed under the License is distributed on an "AS IS" BASIS,
15  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16  * See the License for the specific language governing permissions and
17  * limitations under the License.
18  *
19  * SPDX-License-Identifier: Apache-2.0
20  * ============LICENSE_END=========================================================
21  */
22
23 package org.onap.policy.apex.core.infrastructure.java.compile.singleclass;
24
25 import java.util.Arrays;
26 import java.util.List;
27 import javax.tools.Diagnostic;
28 import javax.tools.DiagnosticCollector;
29 import javax.tools.JavaCompiler;
30 import javax.tools.JavaFileObject;
31 import javax.tools.ToolProvider;
32 import org.onap.policy.apex.core.infrastructure.java.JavaHandlingException;
33 import org.slf4j.ext.XLogger;
34 import org.slf4j.ext.XLoggerFactory;
35
36 /**
37  * The Class SingleClassBuilder is used to compile the Java code for a Java object and to create an instance of the
38  * object.
39  *
40  * @author Liam Fallon (liam.fallon@ericsson.com)
41  */
42 public class SingleClassBuilder {
43     // Logger for this class
44     private static final XLogger LOGGER = XLoggerFactory.getXLogger(SingleClassBuilder.class);
45
46     // The class name and source code for the class that we are compiling and instantiating
47     private final String className;
48     private final String sourceCode;
49
50     // This specialized JavaFileManager handles class loading for the single Java class
51     private SingleFileManager singleFileManager = null;
52
53     /**
54      * Instantiates a new single class builder.
55      *
56      * @param className the class name
57      * @param sourceCode the source code
58      */
59     public SingleClassBuilder(final String className, final String sourceCode) {
60         // Save the fields of the class
61         this.className = className;
62         this.sourceCode = sourceCode;
63     }
64
65     /**
66      * Compile the single class into byte code.
67      *
68      * @throws JavaHandlingException Thrown on compilation errors or handling errors on the single Java class
69      */
70     public void compile() throws JavaHandlingException {
71         // Get the list of compilation units, there is only one here
72         final List<? extends JavaFileObject> compilationUnits =
73                 Arrays.asList(new SingleClassCompilationUnit(className, sourceCode));
74
75         // Allows us to get diagnostics from the compilation
76         final DiagnosticCollector<JavaFileObject> diagnosticListener = new DiagnosticCollector<>();
77
78         // Get the Java compiler
79         final var compiler = ToolProvider.getSystemJavaCompiler();
80
81         // Set up the target file manager and call the compiler
82         singleFileManager = new SingleFileManager(compiler, new SingleClassByteCodeFileObject(className));
83         final JavaCompiler.CompilationTask task =
84                 compiler.getTask(null, singleFileManager, diagnosticListener, null, null, compilationUnits);
85
86         // Check if the compilation worked
87         if (Boolean.FALSE.equals(task.call())) {
88             final var builder = new StringBuilder();
89             for (final Diagnostic<? extends JavaFileObject> diagnostic : diagnosticListener.getDiagnostics()) {
90                 builder.append("code:");
91                 builder.append(diagnostic.getCode());
92                 builder.append(", kind:");
93                 builder.append(diagnostic.getKind());
94                 builder.append(", position:");
95                 builder.append(diagnostic.getPosition());
96                 builder.append(", start position:");
97                 builder.append(diagnostic.getStartPosition());
98                 builder.append(", end position:");
99                 builder.append(diagnostic.getEndPosition());
100                 builder.append(", source:");
101                 builder.append(diagnostic.getSource());
102                 builder.append(", message:");
103                 builder.append(diagnostic.getMessage(null));
104                 builder.append("\n");
105             }
106
107             String message = "error compiling Java code for class \"" + className + "\": " + builder.toString();
108             LOGGER.warn(message);
109             throw new JavaHandlingException(message);
110         }
111     }
112
113     /**
114      * Create a new instance of the Java class using its byte code definition.
115      *
116      * @return A new instance of the object
117      * @throws JavaHandlingException on errors creating the object
118      */
119     public Object createObject()
120             throws InstantiationException, IllegalAccessException, ClassNotFoundException, JavaHandlingException {
121         if (singleFileManager == null) {
122             String message = "error instantiating instance for class \"" + className + "\": code may not be compiled";
123             LOGGER.warn(message);
124             throw new JavaHandlingException(message);
125         }
126
127         try {
128             return singleFileManager.getClassLoader(null).findClass(className).getDeclaredConstructor().newInstance();
129         } catch (Exception e) {
130             return new JavaHandlingException("could not create java class", e);
131         }
132
133     }
134 }