blob: 6fa483f94c2e76f9ad494a5aaf980d5741e36026 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2018 Oracle and/or its affiliates. All rights reserved.
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v1.0 and Eclipse Distribution License v. 1.0
* which accompanies this distribution.
* The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v10.html
* and the Eclipse Distribution License is available at
* http://www.eclipse.org/org/documents/edl-v10.php.
*
* Contributors:
* 02/17/2018-2.7.2 Lukas Jungmann
* - 531305: Canonical model generator fails to run on JDK9
******************************************************************************/
package org.eclipse.persistence.jpa.test.modelgen;
import java.io.BufferedWriter;
import java.io.File;
import java.io.IOException;
import java.io.PrintWriter;
import java.net.URI;
import java.net.URL;
import java.nio.file.FileVisitResult;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.SimpleFileVisitor;
import java.nio.file.StandardOpenOption;
import java.nio.file.attribute.BasicFileAttributes;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import javax.persistence.Entity;
import javax.tools.Diagnostic;
import javax.tools.DiagnosticCollector;
import javax.tools.JavaCompiler;
import javax.tools.JavaCompiler.CompilationTask;
import javax.tools.JavaFileObject;
import javax.tools.SimpleJavaFileObject;
import javax.tools.StandardJavaFileManager;
import javax.tools.StandardLocation;
import javax.tools.ToolProvider;
import org.eclipse.persistence.internal.jpa.modelgen.CanonicalModelProcessor;
import org.junit.Assert;
import org.junit.BeforeClass;
import org.junit.Test;
public class TestProcessor {
@BeforeClass
public static void prepare() throws IOException {
File testRoot = new File(System.getProperty("run.dir"));
if (testRoot.exists() && testRoot.isDirectory()) {
for (File testDir: testRoot.listFiles()) {
delete(testDir);
}
}
}
@Test
public void testProc() throws Exception {
File runDir = new File(System.getProperty("run.dir"), "testproc");
File srcOut = new File(runDir, "src");
srcOut.mkdirs();
File cpDir = new File(runDir, "cp");
cpDir.mkdirs();
File pxml = new File(cpDir, "META-INF/persistence.xml");
pxml.getParentFile().mkdirs();
try (BufferedWriter writer = Files.newBufferedWriter(pxml.toPath(), StandardOpenOption.CREATE_NEW, StandardOpenOption.WRITE)) {
writer.write(PXML, 0, PXML.length());
} catch (IOException x) {
throw x;
}
JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
DiagnosticCollector<JavaFileObject> diagnostics = new DiagnosticCollector<JavaFileObject>();
StandardJavaFileManager sfm = compiler.getStandardFileManager(diagnostics, null, null);
URL apiUrl = Entity.class.getProtectionDomain().getCodeSource().getLocation();
sfm.setLocation(StandardLocation.CLASS_PATH, Arrays.asList(new File(apiUrl.getFile()), cpDir));
sfm.setLocation(StandardLocation.SOURCE_OUTPUT, Collections.singleton(srcOut));
sfm.setLocation(StandardLocation.CLASS_OUTPUT, Arrays.asList(cpDir));
TestFO entity = new TestFO("org.Sample",
"package org; import javax.persistence.Entity; @Entity public class Sample { public Sample() {} public int getX() {return 1;}}");
TestFO nonEntity = new TestFO("org.NotE",
"package org; import javax.persistence.Entity; public class NotE extends some.IF { public NotE() {} @custom.Ann public external.Cls getW() {return new Object();}}");
TestFO generated8 = new TestFO("org.Gen8",
"package org; import javax.annotation.Generated; @Generated(\"com.example.Generator\") public class Gen8 { public Gen8() {} public int getY() {return 42;}}");
TestFO generated9 = new TestFO("org.Gen9",
"package org; @javax.annotation.processing.Generated(\"com.example.Generator\") public class Gen9 { public Gen9() {} public int getZ() {return 9*42;}}");
CompilationTask task = compiler.getTask(new PrintWriter(System.out), sfm, diagnostics,
Arrays.asList("-proc:only", "-Aeclipselink.logging.level.processor=OFF", "-Aeclipselink.canonicalmodel.use_static_factory=false"), null,
Arrays.asList(entity, nonEntity, generated8, generated9));
CanonicalModelProcessor modelProcessor = new CanonicalModelProcessor();
task.setProcessors(Collections.singleton(modelProcessor));
task.call();
for ( Diagnostic<? extends JavaFileObject> diagnostic : diagnostics.getDiagnostics()) {
System.out.println(diagnostic);
}
Assert.assertTrue("Model file not generated", new File(srcOut, "org/Sample_.java").exists());
}
@Test
public void testProcessorLoggingOffFromCmdLine() throws Exception {
verifyLogging("testProcessorLoggingOffFromCmdLine", PXML, false,
"-Aeclipselink.logging.level.processor=OFF");
}
@Test
public void testGlobalLoggingOffFromCmdLine() throws Exception {
verifyLogging("testGlobalLoggingOffFromCmdLine", PXML, false,
"-Aeclipselink.logging.level=OFF");
}
@Test
public void testProcessorLoggingOffFromPU() throws Exception {
final String pu = buildPU("testProcessorLoggingOffFromPU",
new Property("eclipselink.logging.level.processor", "OFF"));
// Turning logging off from PU can't remove messages logged before PU properties are processed.
verifyLogging("testProcessorLoggingOffFromPU", pu, true);
}
@Test
public void testGlobalLoggingOffFromPU() throws Exception {
final String pu = buildPU("testGlobalLoggingOffFromPU",
new Property("eclipselink.logging.level", "OFF"));
// Turning logging off from PU can't remove messages logged before PU properties are processed.
verifyLogging("testGlobalLoggingOffFromPU", pu, true);
}
@Test
public void testProcessorLoggingFinestFromCmdLine() throws Exception {
verifyLogging("testProcessorLoggingFinestFromCmdLine", PXML, true,
"-Aeclipselink.logging.level.processor=FINEST");
}
@Test
public void testGlobalLoggingFinestFromCmdLine() throws Exception {
verifyLogging("testGlobalLoggingFinestFromCmdLine", PXML, true,
"-Aeclipselink.logging.level=FINEST");
}
@Test
public void testProcessorLoggingFinestFromPU() throws Exception {
final String pu = buildPU("testProcessorLoggingFinestFromPU",
new Property("eclipselink.logging.level.processor", "FINEST"));
verifyLogging("testProcessorLoggingFinestFromPU", pu, true);
}
@Test
public void testGlobalLoggingFinestFromPU() throws Exception {
final String pu = buildPU("testGlobalLoggingFinestFromPU",
new Property("eclipselink.logging.level", "FINEST"));
verifyLogging("testGlobalLoggingFinestFromPU", pu, true);
}
/**
* Verify logging output suppression
* @param testName name of the test
* @param pu persistence unit {@code String}
* @param whether there should be logging messages in the output or not
* @param options compiler options
* @throws Exception
*/
private void verifyLogging(final String testName, final String pu, final boolean haveMsgs, final String... options) throws Exception {
File runDir = new File(System.getProperty("run.dir"), testName);
File srcOut = new File(runDir, "src");
srcOut.mkdirs();
File cpDir = new File(runDir, "cp");
cpDir.mkdirs();
File pxml = new File(cpDir, "META-INF/persistence.xml");
pxml.getParentFile().mkdirs();
try (BufferedWriter writer = Files.newBufferedWriter(pxml.toPath(), StandardOpenOption.CREATE_NEW, StandardOpenOption.WRITE)) {
writer.write(pu, 0, pu.length());
} catch (IOException x) {
throw x;
}
JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
DiagnosticCollector<JavaFileObject> diagnostics = new DiagnosticCollector<JavaFileObject>();
StandardJavaFileManager sfm = compiler.getStandardFileManager(diagnostics, null, null);
URL apiUrl = Entity.class.getProtectionDomain().getCodeSource().getLocation();
sfm.setLocation(StandardLocation.CLASS_PATH, Arrays.asList(new File(apiUrl.getFile()), cpDir));
sfm.setLocation(StandardLocation.SOURCE_OUTPUT, Collections.singleton(srcOut));
sfm.setLocation(StandardLocation.CLASS_OUTPUT, Arrays.asList(cpDir));
TestFO entity = new TestFO("org.Sample",
"package org; import javax.persistence.Entity; @Entity public class Sample { public Sample() {} public int getX() {return 1;}}");
List<String> optionsList = new ArrayList<>(options != null ? options.length + 2 : 2);
optionsList.add("-proc:only");
optionsList.add("-Aeclipselink.canonicalmodel.use_static_factory=false");
for (String option : options) {
optionsList.add(option);
}
CompilationTask task = compiler.getTask(
new PrintWriter(System.out), sfm, diagnostics, optionsList, null,
Arrays.asList(entity));
CanonicalModelProcessor modelProcessor = new CanonicalModelProcessor();
task.setProcessors(Collections.singleton(modelProcessor));
task.call();
for ( Diagnostic<? extends JavaFileObject> diagnostic : diagnostics.getDiagnostics()) {
System.out.println(diagnostic);
}
if (haveMsgs) {
Assert.assertFalse("Log messages should be generated", diagnostics.getDiagnostics().isEmpty());
} else {
Assert.assertTrue("No log message should be generated", diagnostics.getDiagnostics().isEmpty());
}
}
private static class TestFO extends SimpleJavaFileObject {
private final String text;
public TestFO(String name, String code) {
super(URI.create("string:///" + name.replace('.','/') + Kind.SOURCE.extension),
Kind.SOURCE);
this.text = code;
}
@Override
public CharSequence getCharContent(boolean ignoreEncodingErrors) {
return text;
}
}
private static final String PXML = "<persistence xmlns=\"http://xmlns.jcp.org/xml/ns/persistence\"\n" +
" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n" +
" xsi:schemaLocation=\"http://xmlns.jcp.org/xml/ns/persistence\n" +
" http://xmlns.jcp.org/xml/ns/persistence/persistence_2_2.xsd\"\n" +
" version=\"2.2\">\n" +
" <persistence-unit name=\"sample-pu\" transaction-type=\"RESOURCE_LOCAL\">\n" +
" <provider>org.eclipse.persistence.jpa.PersistenceProvider</provider>\n" +
" <exclude-unlisted-classes>false</exclude-unlisted-classes>\n" +
" <properties>\n" +
" </properties>\n" +
" </persistence-unit>\n" +
"</persistence>";
private static final String PXML_LOG_BEG =
"<persistence xmlns=\"http://xmlns.jcp.org/xml/ns/persistence\"\n" +
" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n" +
" xsi:schemaLocation=\"http://xmlns.jcp.org/xml/ns/persistence\n" +
" http://xmlns.jcp.org/xml/ns/persistence/persistence_2_2.xsd\"\n" +
" version=\"2.2\">\n" +
" <persistence-unit name=\"";
private static final String PXML_LOG_MID =
"\" transaction-type=\"RESOURCE_LOCAL\">\n" +
" <provider>org.eclipse.persistence.jpa.PersistenceProvider</provider>\n" +
" <exclude-unlisted-classes>false</exclude-unlisted-classes>\n" +
" <properties>\n";
private static final String PXML_LOG_END =
" </properties>\n" +
" </persistence-unit>\n" +
"</persistence>";
/**
* Simple property holding class.
*/
private static final class Property {
private final String name;
private final String value;
private Property(final String name, final String value) {
this.name = name;
this.value = value;
}
}
/**
* Builds persistence unit with properties.
* @param name persistence unit name
* @param properties properties to be added to persistence unit
* @return persistence unit with specified properties
*/
private static String buildPU(final String name, Property ... properties) {
int len = PXML_LOG_BEG.length() + PXML_LOG_MID.length() + PXML_LOG_END.length() + name.length();
for (Property property : properties) {
len += property.name.length() + property.value.length() + 43;
}
final StringBuilder sb = new StringBuilder(len);
sb.append(PXML_LOG_BEG);
sb.append(name);
sb.append(PXML_LOG_MID);
for (Property property : properties) {
sb.append(" <property name=\"");
sb.append(property.name);
sb.append("\" value=\"");
sb.append(property.value);
sb.append("\"/>\n");
}
sb.append(PXML_LOG_END);
return sb.toString();
}
private static void delete(File dir) throws IOException {
Files.walkFileTree(dir.toPath(), new SimpleFileVisitor<Path>() {
@Override
public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
Files.delete(file);
return FileVisitResult.CONTINUE;
}
@Override
public FileVisitResult postVisitDirectory(Path dir, IOException exc) throws IOException {
Files.delete(dir);
return FileVisitResult.CONTINUE;
}
});
}
}