5765eee01f1889d48acf652ae4621d5e668b8783
[policy/apex-pdp.git] /
1 /*-
2  * ============LICENSE_START=======================================================
3  *  Copyright (C) 2016-2018 Ericsson. All rights reserved.
4  * ================================================================================
5  * Licensed under the Apache License, Version 2.0 (the "License");
6  * you may not use this file except in compliance with the License.
7  * You may obtain a copy of the License at
8  *
9  *      http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  *
17  * SPDX-License-Identifier: Apache-2.0
18  * ============LICENSE_END=========================================================
19  */
20
21 package org.onap.policy.core.infrastructure.java.compile.singleclass;
22
23 import java.util.Arrays;
24 import java.util.List;
25
26 import javax.tools.Diagnostic;
27 import javax.tools.DiagnosticCollector;
28 import javax.tools.JavaCompiler;
29 import javax.tools.JavaFileObject;
30 import javax.tools.ToolProvider;
31
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 JavaCompiler 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 (!task.call()) {
88             final StringBuilder 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             LOGGER.warn("error compiling Java code for class \"" + className + "\": " + builder.toString());
108             throw new JavaHandlingException(
109                     "error compiling Java code for class \"" + className + "\": " + builder.toString());
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 InstantiationException if an instance of the object cannot be created, for example if the class has no
118      *         default constructor
119      * @throws IllegalAccessException the caller does not have permission to call the class
120      * @throws ClassNotFoundException the byte code for the class is not found in the class loader
121      * @throws JavaHandlingException the java handling exception if the Java class source code is not compiled
122      */
123     public Object createObject()
124             throws InstantiationException, IllegalAccessException, ClassNotFoundException, JavaHandlingException {
125         if (singleFileManager == null) {
126             LOGGER.warn("error instantiating instance for class \"" + className + "\": code may not be compiled");
127             throw new JavaHandlingException(
128                     "error instantiating instance for class \"" + className + "\": code may not be compiled");
129         }
130
131         return singleFileManager.getClassLoader(null).findClass(className).newInstance();
132     }
133 }