Merge remote-tracking branch 'upstream/master'
This commit is contained in:
commit
3319b28b9c
|
@ -216,6 +216,13 @@
|
|||
<artifactId>spring-web</artifactId>
|
||||
<version>4.3.4.RELEASE</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.sun</groupId>
|
||||
<artifactId>tools</artifactId>
|
||||
<version>1.8.0</version>
|
||||
<scope>system</scope>
|
||||
<systemPath>${java.home}/../lib/tools.jar</systemPath>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
|
|
|
@ -0,0 +1,9 @@
|
|||
package com.baeldung.javac;
|
||||
|
||||
import java.lang.annotation.*;
|
||||
|
||||
@Documented
|
||||
@Retention(RetentionPolicy.CLASS)
|
||||
@Target({ElementType.PARAMETER})
|
||||
public @interface Positive {
|
||||
}
|
|
@ -0,0 +1,123 @@
|
|||
package com.baeldung.javac;
|
||||
|
||||
import com.sun.source.tree.MethodTree;
|
||||
import com.sun.source.tree.VariableTree;
|
||||
import com.sun.source.util.*;
|
||||
import com.sun.tools.javac.api.BasicJavacTask;
|
||||
import com.sun.tools.javac.code.TypeTag;
|
||||
import com.sun.tools.javac.tree.JCTree;
|
||||
import com.sun.tools.javac.tree.TreeMaker;
|
||||
import com.sun.tools.javac.util.Context;
|
||||
import com.sun.tools.javac.util.Name;
|
||||
import com.sun.tools.javac.util.Names;
|
||||
|
||||
import javax.tools.JavaCompiler;
|
||||
import java.util.*;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import static com.sun.tools.javac.util.List.nil;
|
||||
|
||||
/**
|
||||
* A {@link JavaCompiler javac} plugin which inserts {@code >= 0} checks into resulting {@code *.class} files
|
||||
* for numeric method parameters marked by {@link Positive}
|
||||
*/
|
||||
public class SampleJavacPlugin implements Plugin {
|
||||
|
||||
public static final String NAME = "MyPlugin";
|
||||
|
||||
private static Set<String> TARGET_TYPES = new HashSet<>(Arrays.asList(
|
||||
// Use only primitive types for simplicity
|
||||
byte.class.getName(), short.class.getName(), char.class.getName(),
|
||||
int.class.getName(), long.class.getName(), float.class.getName(), double.class.getName()));
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return NAME;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void init(JavacTask task, String... args) {
|
||||
Context context = ((BasicJavacTask) task).getContext();
|
||||
task.addTaskListener(new TaskListener() {
|
||||
@Override
|
||||
public void started(TaskEvent e) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void finished(TaskEvent e) {
|
||||
if (e.getKind() != TaskEvent.Kind.PARSE) {
|
||||
return;
|
||||
}
|
||||
e.getCompilationUnit()
|
||||
.accept(new TreeScanner<Void, Void>() {
|
||||
@Override
|
||||
public Void visitMethod(MethodTree method, Void v) {
|
||||
List<VariableTree> parametersToInstrument = method.getParameters()
|
||||
.stream()
|
||||
.filter(SampleJavacPlugin.this::shouldInstrument)
|
||||
.collect(Collectors.toList());
|
||||
if (!parametersToInstrument.isEmpty()) {
|
||||
// There is a possible case that more than one argument is marked by @Positive,
|
||||
// as the checks are added to the method's body beginning, we process parameters RTL
|
||||
// to ensure correct order.
|
||||
Collections.reverse(parametersToInstrument);
|
||||
parametersToInstrument.forEach(p -> addCheck(method, p, context));
|
||||
}
|
||||
// There is a possible case that there is a nested class declared in a method's body,
|
||||
// hence, we want to proceed with method body AST as well.
|
||||
return super.visitMethod(method, v);
|
||||
}
|
||||
}, null);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private boolean shouldInstrument(VariableTree parameter) {
|
||||
return TARGET_TYPES.contains(parameter.getType().toString())
|
||||
&& parameter.getModifiers().getAnnotations()
|
||||
.stream()
|
||||
.anyMatch(a -> Positive.class.getSimpleName().equals(a.getAnnotationType().toString()));
|
||||
}
|
||||
|
||||
private void addCheck(MethodTree method, VariableTree parameter, Context context) {
|
||||
JCTree.JCIf check = createCheck(parameter, context);
|
||||
JCTree.JCBlock body = (JCTree.JCBlock) method.getBody();
|
||||
body.stats = body.stats.prepend(check);
|
||||
}
|
||||
|
||||
private static JCTree.JCIf createCheck(VariableTree parameter, Context context) {
|
||||
TreeMaker factory = TreeMaker.instance(context);
|
||||
Names symbolsTable = Names.instance(context);
|
||||
|
||||
return factory.at(((JCTree) parameter).pos)
|
||||
.If(factory.Parens(createIfCondition(factory, symbolsTable, parameter)),
|
||||
createIfBlock(factory, symbolsTable, parameter),
|
||||
null);
|
||||
}
|
||||
|
||||
private static JCTree.JCBinary createIfCondition(TreeMaker factory, Names symbolsTable, VariableTree parameter) {
|
||||
Name parameterId = symbolsTable.fromString(parameter.getName().toString());
|
||||
return factory.Binary(JCTree.Tag.LE,
|
||||
factory.Ident(parameterId),
|
||||
factory.Literal(TypeTag.INT, 0));
|
||||
}
|
||||
|
||||
private static JCTree.JCBlock createIfBlock(TreeMaker factory, Names symbolsTable, VariableTree parameter) {
|
||||
String parameterName = parameter.getName().toString();
|
||||
Name parameterId = symbolsTable.fromString(parameterName);
|
||||
|
||||
String errorMessagePrefix = String.format("Argument '%s' of type %s is marked by @%s but got '",
|
||||
parameterName, parameter.getType(), Positive.class.getSimpleName());
|
||||
String errorMessageSuffix = "' for it";
|
||||
|
||||
return factory.Block(0, com.sun.tools.javac.util.List.of(
|
||||
factory.Throw(
|
||||
factory.NewClass(null, nil(),
|
||||
factory.Ident(symbolsTable.fromString(IllegalArgumentException.class.getSimpleName())),
|
||||
com.sun.tools.javac.util.List.of(factory.Binary(JCTree.Tag.PLUS,
|
||||
factory.Binary(JCTree.Tag.PLUS, factory.Literal(TypeTag.CLASS, errorMessagePrefix),
|
||||
factory.Ident(parameterId)),
|
||||
factory.Literal(TypeTag.CLASS, errorMessageSuffix))), null))));
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1 @@
|
|||
com.baeldung.javac.SampleJavacPlugin
|
|
@ -0,0 +1,42 @@
|
|||
package com.baeldung.javac;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
|
||||
public class SampleJavacPluginIntegrationTest {
|
||||
|
||||
private static final String CLASS_TEMPLATE =
|
||||
"package com.baeldung.javac;\n" +
|
||||
"\n" +
|
||||
"public class Test {\n" +
|
||||
" public static %1$s service(@Positive %1$s i) {\n" +
|
||||
" return i;\n" +
|
||||
" }\n" +
|
||||
"}\n" +
|
||||
"";
|
||||
|
||||
private TestCompiler compiler = new TestCompiler();
|
||||
private TestRunner runner = new TestRunner();
|
||||
|
||||
@Test(expected = IllegalArgumentException.class)
|
||||
public void givenInt_whenNegative_thenThrowsException() throws Throwable {
|
||||
compileAndRun(double.class,-1);
|
||||
}
|
||||
|
||||
@Test(expected = IllegalArgumentException.class)
|
||||
public void givenInt_whenZero_thenThrowsException() throws Throwable {
|
||||
compileAndRun(int.class,0);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void givenInt_whenPositive_thenSuccess() throws Throwable {
|
||||
assertEquals(1, compileAndRun(int.class, 1));
|
||||
}
|
||||
|
||||
private Object compileAndRun(Class<?> argumentType, Object argument) throws Throwable {
|
||||
String qualifiedClassName = "com.baeldung.javac.Test";
|
||||
byte[] byteCode = compiler.compile(qualifiedClassName, String.format(CLASS_TEMPLATE, argumentType.getName()));
|
||||
return runner.run(byteCode, qualifiedClassName, "service", new Class[] {argumentType}, argument);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,26 @@
|
|||
package com.baeldung.javac;
|
||||
|
||||
import javax.tools.SimpleJavaFileObject;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
import java.net.URI;
|
||||
|
||||
/** Holds compiled byte code in a byte array */
|
||||
public class SimpleClassFile extends SimpleJavaFileObject {
|
||||
|
||||
private ByteArrayOutputStream out;
|
||||
|
||||
public SimpleClassFile(URI uri) {
|
||||
super(uri, Kind.CLASS);
|
||||
}
|
||||
|
||||
@Override
|
||||
public OutputStream openOutputStream() throws IOException {
|
||||
return out = new ByteArrayOutputStream();
|
||||
}
|
||||
|
||||
public byte[] getCompiledBinaries() {
|
||||
return out.toByteArray();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,34 @@
|
|||
package com.baeldung.javac;
|
||||
|
||||
import javax.tools.*;
|
||||
import java.net.URI;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/** Adapts {@link SimpleClassFile} to the {@link JavaCompiler} */
|
||||
public class SimpleFileManager extends ForwardingJavaFileManager<StandardJavaFileManager> {
|
||||
|
||||
private final List<SimpleClassFile> compiled = new ArrayList<>();
|
||||
|
||||
public SimpleFileManager(StandardJavaFileManager delegate) {
|
||||
super(delegate);
|
||||
}
|
||||
|
||||
@Override
|
||||
public JavaFileObject getJavaFileForOutput(Location location,
|
||||
String className,
|
||||
JavaFileObject.Kind kind,
|
||||
FileObject sibling)
|
||||
{
|
||||
SimpleClassFile result = new SimpleClassFile(URI.create("string://" + className));
|
||||
compiled.add(result);
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return compiled binaries processed by the current class
|
||||
*/
|
||||
public List<SimpleClassFile> getCompiled() {
|
||||
return compiled;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,23 @@
|
|||
package com.baeldung.javac;
|
||||
|
||||
import javax.tools.SimpleJavaFileObject;
|
||||
import java.net.URI;
|
||||
|
||||
/** Exposes given test source to the compiler. */
|
||||
public class SimpleSourceFile extends SimpleJavaFileObject {
|
||||
|
||||
private final String content;
|
||||
|
||||
public SimpleSourceFile(String qualifiedClassName, String testSource) {
|
||||
super(URI.create(String.format("file://%s%s",
|
||||
qualifiedClassName.replaceAll("\\.", "/"),
|
||||
Kind.SOURCE.extension)),
|
||||
Kind.SOURCE);
|
||||
content = testSource;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CharSequence getCharContent(boolean ignoreEncodingErrors) {
|
||||
return content;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,35 @@
|
|||
package com.baeldung.javac;
|
||||
|
||||
import javax.tools.JavaCompiler;
|
||||
import javax.tools.ToolProvider;
|
||||
import java.io.StringWriter;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import static java.util.Arrays.asList;
|
||||
import static java.util.Collections.singletonList;
|
||||
|
||||
public class TestCompiler {
|
||||
public byte[] compile(String qualifiedClassName, String testSource) {
|
||||
StringWriter output = new StringWriter();
|
||||
|
||||
JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
|
||||
SimpleFileManager fileManager = new SimpleFileManager(compiler.getStandardFileManager(
|
||||
null,
|
||||
null,
|
||||
null
|
||||
));
|
||||
List<SimpleSourceFile> compilationUnits = singletonList(new SimpleSourceFile(qualifiedClassName, testSource));
|
||||
List<String> arguments = new ArrayList<>();
|
||||
arguments.addAll(asList("-classpath", System.getProperty("java.class.path"),
|
||||
"-Xplugin:" + SampleJavacPlugin.NAME));
|
||||
JavaCompiler.CompilationTask task = compiler.getTask(output,
|
||||
fileManager,
|
||||
null,
|
||||
arguments,
|
||||
null,
|
||||
compilationUnits);
|
||||
task.call();
|
||||
return fileManager.getCompiled().iterator().next().getCompiledBinaries();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,41 @@
|
|||
package com.baeldung.javac;
|
||||
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
public class TestRunner {
|
||||
|
||||
public Object run(byte[] byteCode,
|
||||
String qualifiedClassName,
|
||||
String methodName,
|
||||
Class<?>[] argumentTypes,
|
||||
Object... args)
|
||||
throws Throwable
|
||||
{
|
||||
ClassLoader classLoader = new ClassLoader() {
|
||||
@Override
|
||||
protected Class<?> findClass(String name) throws ClassNotFoundException {
|
||||
return defineClass(name, byteCode, 0, byteCode.length);
|
||||
}
|
||||
};
|
||||
Class<?> clazz;
|
||||
try {
|
||||
clazz = classLoader.loadClass(qualifiedClassName);
|
||||
} catch (ClassNotFoundException e) {
|
||||
throw new RuntimeException("Can't load compiled test class", e);
|
||||
}
|
||||
|
||||
Method method;
|
||||
try {
|
||||
method = clazz.getMethod(methodName, argumentTypes);
|
||||
} catch (NoSuchMethodException e) {
|
||||
throw new RuntimeException("Can't find the 'main()' method in the compiled test class", e);
|
||||
}
|
||||
|
||||
try {
|
||||
return method.invoke(null, args);
|
||||
} catch (InvocationTargetException e) {
|
||||
throw e.getCause();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,141 @@
|
|||
package com.baeldung.string.formatter;
|
||||
|
||||
import java.util.Calendar;
|
||||
import java.util.Formatter;
|
||||
import java.util.GregorianCalendar;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import org.junit.Test;
|
||||
|
||||
public class StringFormatterExampleTests {
|
||||
|
||||
@Test
|
||||
public void givenString_whenFormatSpecifierForCalendar_thenGotExpected() {
|
||||
//Syntax of Format Specifiers for Date/Time Representation
|
||||
Calendar c = new GregorianCalendar(2017, 11, 10);
|
||||
String s = String.format("The date is: %1$tm %1$te,%1$tY", c);
|
||||
|
||||
assertEquals("The date is: 12 10,2017", s);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void givenString_whenGeneralConversion_thenConvertedString() {
|
||||
//General Conversions
|
||||
String s = String.format("The correct answer is %s", false);
|
||||
assertEquals("The correct answer is false", s);
|
||||
|
||||
s = String.format("The correct answer is %b", null);
|
||||
assertEquals("The correct answer is false", s);
|
||||
|
||||
s = String.format("The correct answer is %B", true);
|
||||
assertEquals("The correct answer is TRUE", s);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void givenString_whenCharConversion_thenConvertedString() {
|
||||
//Character Conversions
|
||||
String s = String.format("The correct answer is %c", 'a');
|
||||
assertEquals("The correct answer is a", s);
|
||||
|
||||
s = String.format("The correct answer is %c", null);
|
||||
assertEquals("The correct answer is null", s);
|
||||
|
||||
s = String.format("The correct answer is %C", 'b');
|
||||
assertEquals("The correct answer is B", s);
|
||||
|
||||
s = String.format("The valid unicode character: %c", 0x0400);
|
||||
assertTrue(Character.isValidCodePoint(0x0400));
|
||||
assertEquals("The valid unicode character: Ѐ", s);
|
||||
}
|
||||
|
||||
@Test(expected = java.util.IllegalFormatCodePointException.class)
|
||||
public void givenString_whenIllegalCodePointForConversion_thenError() {
|
||||
String s = String.format("The valid unicode character: %c", 0x11FFFF);
|
||||
assertFalse(Character.isValidCodePoint(0x11FFFF));
|
||||
assertEquals("The valid unicode character: Ā", s);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void givenString_whenNumericIntegralConversion_thenConvertedString() {
|
||||
//Numeric Integral Conversions
|
||||
String s = String.format("The number 25 in decimal = %d", 25);
|
||||
assertEquals("The number 25 in decimal = 25", s);
|
||||
|
||||
s = String.format("The number 25 in octal = %o", 25);
|
||||
assertEquals("The number 25 in octal = 31", s);
|
||||
|
||||
s = String.format("The number 25 in hexadecimal = %x", 25);
|
||||
assertEquals("The number 25 in hexadecimal = 19", s);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void givenString_whenNumericFloatingConversion_thenConvertedString() {
|
||||
//Numeric Floating-point Conversions
|
||||
String s = String.format("The computerized scientific format of 10000.00 "
|
||||
+ "= %e", 10000.00);
|
||||
assertEquals("The computerized scientific format of 10000.00 = 1.000000e+04", s);
|
||||
|
||||
s = String.format("The decimal format of 10.019 = %f", 10.019);
|
||||
assertEquals("The decimal format of 10.019 = 10.019000", s);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void givenString_whenLineSeparatorConversion_thenConvertedString() {
|
||||
//Line Separator Conversion
|
||||
String s = String.format("First Line %nSecond Line");
|
||||
assertEquals("First Line \n"
|
||||
+ "Second Line", s);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void givenString_whenSpecifyFlag_thenGotFormattedString() {
|
||||
//Without left-justified flag
|
||||
String s = String.format("Without left justified flag: %5d", 25);
|
||||
assertEquals("Without left justified flag: 25", s);
|
||||
|
||||
//Using left-justified flag
|
||||
s = String.format("With left justified flag: %-5d", 25);
|
||||
assertEquals("With left justified flag: 25 ", s);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void givenString_whenSpecifyPrecision_thenGotExpected() {
|
||||
|
||||
//Precision
|
||||
String s = String.format("Output of 25.09878 with Precision 2: %.2f", 25.09878);
|
||||
assertEquals("Output of 25.09878 with Precision 2: 25.10", s);
|
||||
|
||||
s = String.format("Output of general conversion type with Precision 2: %.2b", true);
|
||||
assertEquals("Output of general conversion type with Precision 2: tr", s);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void givenString_whenSpecifyArgumentIndex_thenGotExpected() {
|
||||
Calendar c = new GregorianCalendar(2017, 11, 10);
|
||||
//Argument_Index
|
||||
String s = String.format("The date is: %1$tm %1$te,%1$tY", c);
|
||||
assertEquals("The date is: 12 10,2017", s);
|
||||
|
||||
s = String.format("The date is: %1$tm %<te,%<tY", c);
|
||||
assertEquals("The date is: 12 10,2017", s);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void givenAppendable_whenCreateFormatter_thenFormatterWorksOnAppendable() {
|
||||
//Using String Formatter with Appendable
|
||||
StringBuilder sb = new StringBuilder();
|
||||
Formatter formatter = new Formatter(sb);
|
||||
formatter.format("I am writting to a %1$s Instance.", sb.getClass());
|
||||
|
||||
assertEquals("I am writting to a class java.lang.StringBuilder Instance.", sb.toString());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void givenString_whenNoArguments_thenExpected() {
|
||||
//Using String Formatter without arguments
|
||||
String s = String.format("John scored 90%% in Fall semester");
|
||||
assertEquals("John scored 90% in Fall semester", s);
|
||||
}
|
||||
|
||||
}
|
|
@ -16,32 +16,29 @@ import wildfly.beans.UserBeanLocal;
|
|||
* Servlet implementation class TestEJBServlet
|
||||
*/
|
||||
public class TestEJBServlet extends HttpServlet {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@EJB
|
||||
private UserBeanLocal userBean;
|
||||
@EJB
|
||||
private UserBeanLocal userBean;
|
||||
|
||||
protected void doGet(HttpServletRequest request, HttpServletResponse response)
|
||||
throws ServletException, IOException {
|
||||
List<User> users = userBean.getUsers();
|
||||
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
|
||||
List<User> users = userBean.getUsers();
|
||||
|
||||
PrintWriter out = response.getWriter();
|
||||
PrintWriter out = response.getWriter();
|
||||
|
||||
out.println("<html>");
|
||||
out.println("<head><title>Users</title></head>");
|
||||
out.println("<body>");
|
||||
out.println("<center><h1>List of users:</h1>");
|
||||
out.println("<table border=\"1\" align=\"center\" style=\"width:50%\">");
|
||||
for (User user : users) {
|
||||
out.println("<tr>");
|
||||
out.print("<td>" + user.getUsername() + "</td>");
|
||||
out.print("<td>" + user.getEmail() + "</td>");
|
||||
out.println("</tr>");
|
||||
}
|
||||
}
|
||||
out.println("<html>");
|
||||
out.println("<head><title>Users</title></head>");
|
||||
out.println("<body>");
|
||||
out.println("<center><h1>List of users:</h1>");
|
||||
out.println("<table border=\"1\" align=\"center\" style=\"width:50%\">");
|
||||
for (User user : users) {
|
||||
out.println("<tr>");
|
||||
out.print("<td>" + user.getUsername() + "</td>");
|
||||
out.print("<td>" + user.getEmail() + "</td>");
|
||||
out.println("</tr>");
|
||||
}
|
||||
}
|
||||
|
||||
protected void doPost(HttpServletRequest request, HttpServletResponse response)
|
||||
throws ServletException, IOException {
|
||||
doGet(request, response);
|
||||
}
|
||||
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
|
||||
doGet(request, response);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
## Relevant articles:
|
||||
|
||||
- [Dynamic Mapping with Hibernate](http://www.baeldung.com/hibernate-dynamic-mapping)
|
||||
- [An Overview of Identifiers in Hibernate](http://www.baeldung.com/hibernate-identifiers)
|
||||
|
|
|
@ -0,0 +1,55 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
|
||||
<!-- com.baeldung/osgi-intro-sample-activator/1.0-SNAPSHOT -->
|
||||
<parent>
|
||||
<artifactId>osgi-intro</artifactId>
|
||||
<groupId>com.baeldung</groupId>
|
||||
<version>1.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<!-- Please, note this is not the usual 'jar'. -->
|
||||
<packaging>bundle</packaging>
|
||||
|
||||
<artifactId>osgi-intro-sample-activator</artifactId>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.osgi</groupId>
|
||||
<artifactId>org.osgi.core</artifactId>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.felix</groupId>
|
||||
<artifactId>maven-bundle-plugin</artifactId>
|
||||
<extensions>true</extensions>
|
||||
<configuration>
|
||||
<instructions>
|
||||
<Bundle-SymbolicName>${project.groupId}.${project.artifactId}</Bundle-SymbolicName>
|
||||
<Bundle-Name>${project.artifactId}</Bundle-Name>
|
||||
<Bundle-Version>${project.version}</Bundle-Version>
|
||||
|
||||
<!-- Qualified name of the class that exposes the activator iface. -->
|
||||
<Bundle-Activator>com.baeldung.osgi.sample.activator.HelloWorld</Bundle-Activator>
|
||||
|
||||
<!-- One important thing to note:
|
||||
since you are not exporting the package "com.baeldung.osgi.sample.activator",
|
||||
you should at least add it to the Private-Package instruction.
|
||||
Otherwise, the classes inside the package will not be copied to your bundle,
|
||||
as the default value of this instruction is empty. -->
|
||||
|
||||
<Private-Package>com.baeldung.osgi.sample.activator</Private-Package>
|
||||
|
||||
</instructions>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
|
||||
</project>
|
|
@ -0,0 +1,16 @@
|
|||
package com.baeldung.osgi.sample.activator;
|
||||
|
||||
import org.osgi.framework.BundleActivator;
|
||||
import org.osgi.framework.BundleContext;
|
||||
|
||||
public class HelloWorld implements BundleActivator {
|
||||
|
||||
public void start(BundleContext ctx) {
|
||||
System.out.println("Hello World.");
|
||||
}
|
||||
|
||||
public void stop(BundleContext bundleContext) {
|
||||
System.out.println("Goodbye World.");
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,49 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<parent>
|
||||
<artifactId>osgi-intro</artifactId>
|
||||
<groupId>com.baeldung</groupId>
|
||||
<version>1.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<!-- mvn:com.baeldung/osgi-intro-sample-client/1.0-SNAPSHOT -->
|
||||
<artifactId>osgi-intro-sample-client</artifactId>
|
||||
|
||||
<packaging>bundle</packaging>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>com.baeldung</groupId>
|
||||
<artifactId>osgi-intro-sample-service</artifactId>
|
||||
<version>1.0-SNAPSHOT</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.osgi</groupId>
|
||||
<artifactId>org.osgi.core</artifactId>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.felix</groupId>
|
||||
<artifactId>maven-bundle-plugin</artifactId>
|
||||
<configuration>
|
||||
<instructions>
|
||||
<Bundle-SymbolicName>${project.groupId}.${project.artifactId}</Bundle-SymbolicName>
|
||||
<Bundle-Name>${project.artifactId}</Bundle-Name>
|
||||
<Bundle-Version>${project.version}</Bundle-Version>
|
||||
<Bundle-Activator>com.baeldung.osgi.sample.client.Client</Bundle-Activator>
|
||||
|
||||
<Private-Package>com.baeldung.osgi.sample.client</Private-Package>
|
||||
|
||||
</instructions>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
|
||||
</project>
|
|
@ -0,0 +1,44 @@
|
|||
package com.baeldung.osgi.sample.client;
|
||||
|
||||
import com.baeldung.osgi.sample.service.definition.Greeter;
|
||||
import org.osgi.framework.*;
|
||||
|
||||
public class Client implements BundleActivator, ServiceListener {
|
||||
|
||||
private BundleContext ctx;
|
||||
private ServiceReference serviceReference;
|
||||
|
||||
public void start(BundleContext ctx) {
|
||||
this.ctx = ctx;
|
||||
try {
|
||||
ctx.addServiceListener(this, "(objectclass=" + Greeter.class.getName() + ")");
|
||||
} catch (InvalidSyntaxException ise) {
|
||||
ise.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
public void stop(BundleContext bundleContext) {
|
||||
if (serviceReference != null) {
|
||||
ctx.ungetService(serviceReference);
|
||||
}
|
||||
this.ctx = null;
|
||||
}
|
||||
|
||||
public void serviceChanged(ServiceEvent serviceEvent) {
|
||||
int type = serviceEvent.getType();
|
||||
switch (type) {
|
||||
case (ServiceEvent.REGISTERED):
|
||||
System.out.println("Notification of service registered.");
|
||||
serviceReference = serviceEvent.getServiceReference();
|
||||
Greeter service = (Greeter) (ctx.getService(serviceReference));
|
||||
System.out.println(service.sayHiTo("John"));
|
||||
break;
|
||||
case (ServiceEvent.UNREGISTERING):
|
||||
System.out.println("Notification of service unregistered.");
|
||||
ctx.ungetService(serviceEvent.getServiceReference());
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,46 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
|
||||
<!-- mvn:com.baeldung/osgi-intro-sample-service/1.0-SNAPSHOT -->
|
||||
<parent>
|
||||
<artifactId>osgi-intro</artifactId>
|
||||
<groupId>com.baeldung</groupId>
|
||||
<version>1.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<artifactId>osgi-intro-sample-service</artifactId>
|
||||
|
||||
<!-- Please, note this is not the usual 'jar'. -->
|
||||
<packaging>bundle</packaging>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.osgi</groupId>
|
||||
<artifactId>org.osgi.core</artifactId>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.felix</groupId>
|
||||
<artifactId>maven-bundle-plugin</artifactId>
|
||||
<extensions>true</extensions>
|
||||
<configuration>
|
||||
<instructions>
|
||||
<Bundle-SymbolicName>${project.groupId}.${project.artifactId}</Bundle-SymbolicName>
|
||||
<Bundle-Name>${project.artifactId}</Bundle-Name>
|
||||
<Bundle-Version>${project.version}</Bundle-Version>
|
||||
<Bundle-Activator>com.baeldung.osgi.sample.service.implementation.GreeterImpl</Bundle-Activator>
|
||||
<Private-Package>com.baeldung.osgi.sample.service.implementation</Private-Package>
|
||||
<Export-Package>com.baeldung.osgi.sample.service.definition</Export-Package>
|
||||
</instructions>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
|
||||
</project>
|
|
@ -0,0 +1,7 @@
|
|||
package com.baeldung.osgi.sample.service.definition;
|
||||
|
||||
public interface Greeter {
|
||||
|
||||
public String sayHiTo(String name);
|
||||
|
||||
}
|
|
@ -0,0 +1,30 @@
|
|||
package com.baeldung.osgi.sample.service.implementation;
|
||||
|
||||
import com.baeldung.osgi.sample.service.definition.Greeter;
|
||||
import org.osgi.framework.BundleActivator;
|
||||
import org.osgi.framework.BundleContext;
|
||||
import org.osgi.framework.ServiceReference;
|
||||
import org.osgi.framework.ServiceRegistration;
|
||||
|
||||
import java.util.Hashtable;
|
||||
|
||||
public class GreeterImpl implements Greeter, BundleActivator {
|
||||
|
||||
private ServiceReference<Greeter> reference;
|
||||
private ServiceRegistration<Greeter> registration;
|
||||
|
||||
@Override public String sayHiTo(String name) {
|
||||
return "Hello " + name;
|
||||
}
|
||||
|
||||
@Override public void start(BundleContext context) throws Exception {
|
||||
System.out.println("Registering service.");
|
||||
registration = context.registerService(Greeter.class, new GreeterImpl(), new Hashtable<String, String>());
|
||||
reference = registration.getReference();
|
||||
}
|
||||
|
||||
@Override public void stop(BundleContext context) throws Exception {
|
||||
System.out.println("Unregistering service.");
|
||||
registration.unregister();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,87 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<artifactId>osgi-intro</artifactId>
|
||||
<packaging>pom</packaging>
|
||||
<version>1.0-SNAPSHOT</version>
|
||||
<modules>
|
||||
<module>osgi-intro-sample-activator</module>
|
||||
<module>osgi-intro-sample-service</module>
|
||||
<module>osgi-intro-sample-client</module>
|
||||
</modules>
|
||||
|
||||
<parent>
|
||||
<groupId>com.baeldung</groupId>
|
||||
<artifactId>parent-modules</artifactId>
|
||||
<version>1.0.0-SNAPSHOT</version>
|
||||
<relativePath>../..</relativePath>
|
||||
</parent>
|
||||
|
||||
<dependencyManagement>
|
||||
<dependencies>
|
||||
|
||||
<dependency>
|
||||
<groupId>${project.groupId}</groupId>
|
||||
<artifactId>osgi-intro-client</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>${project.groupId}</groupId>
|
||||
<artifactId>osgi-intro-service</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>${project.groupId}</groupId>
|
||||
<artifactId>osgi-intro-gxyz</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>${project.groupId}</groupId>
|
||||
<artifactId>osgi-intro-mapquest</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.squareup.okhttp3</groupId>
|
||||
<artifactId>okhttp</artifactId>
|
||||
<version>3.9.0</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>javax.json</groupId>
|
||||
<artifactId>javax.json-api</artifactId>
|
||||
<version>1.1</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.glassfish</groupId>
|
||||
<artifactId>javax.json</artifactId>
|
||||
<version>1.1</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.osgi</groupId>
|
||||
<artifactId>org.osgi.core</artifactId>
|
||||
<version>5.0.0</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</dependencyManagement>
|
||||
|
||||
<build>
|
||||
<pluginManagement>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.felix</groupId>
|
||||
<artifactId>maven-bundle-plugin</artifactId>
|
||||
<version>1.4.0</version>
|
||||
<extensions>true</extensions>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</pluginManagement>
|
||||
</build>
|
||||
|
||||
</project>
|
|
@ -0,0 +1,91 @@
|
|||
OSGi
|
||||
====
|
||||
|
||||
Info
|
||||
---
|
||||
|
||||
com.baeldung.osgi
|
||||
com.baeldung.osgi.sample.activator
|
||||
|
||||
Apache Felix
|
||||
---
|
||||
|
||||
|
||||
### Start
|
||||
|
||||
Download Apache Felix Framework Distribution
|
||||
from <https://felix.apache.org/downloads.cgi>
|
||||
org.apache.felix.main.distribution-5.6.8
|
||||
|
||||
No! The Apache Karaf container is best.
|
||||
Download it from: <https://karaf.apache.org/download.html>
|
||||
|
||||
Download a binary distribution and unzip wherever you prefer.
|
||||
|
||||
Then run
|
||||
|
||||
bin\karaf.bat start
|
||||
|
||||
|
||||
Unzip, pay attention to the files not being clipped(!).
|
||||
|
||||
system:exit
|
||||
|
||||
exit!
|
||||
|
||||
shutdown -h
|
||||
|
||||
or `^D`
|
||||
|
||||
### clean start
|
||||
|
||||
full clean, remove "data directory "
|
||||
|
||||
or...
|
||||
|
||||
bin\karaf.bat clean
|
||||
|
||||
bin\start.bat clean
|
||||
|
||||
### run mode
|
||||
|
||||
can be launched in
|
||||
|
||||
- the "regular" mode starts Apache Karaf in foreground, including the shell console.
|
||||
- the "server" mode starts Apache Karaf in foreground, without the shell console.
|
||||
- the "background" mode starts Apache Karaf in background.
|
||||
|
||||
### Logging
|
||||
|
||||
https://karaf.apache.org/manual/latest/#_log
|
||||
|
||||
can be logged to console
|
||||
|
||||
|
||||
### Bundle deploy
|
||||
|
||||
bundle:install mvn:com.baeldung/osgi-intro-sample-activator/1.0-SNAPSHOT
|
||||
|
||||
install mvn:com.baeldung/osgi-intro-sample-service/1.0-SNAPSHOT
|
||||
install mvn:com.baeldung/osgi-intro-sample-client/1.0-SNAPSHOT
|
||||
|
||||
Eclipse's Equinox
|
||||
====
|
||||
|
||||
Eclipse's OSGi platform
|
||||
http://www.eclipse.org/equinox/
|
||||
|
||||
http://www.eclipse.org/equinox/documents/quickstart-framework.php
|
||||
|
||||
click on "download"
|
||||
|
||||
Latest Release
|
||||
Oxygen.1 Wed, 6 Sep 2017 -- 17:00 (-0400)
|
||||
|
||||
org.eclipse.osgi_3.12.1.v20170821-1548.jar
|
||||
|
||||
= = NOT GOOD = =
|
||||
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,55 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
|
||||
<!-- com.baeldung/osgi-intro-sample-activator/1.0-SNAPSHOT -->
|
||||
<parent>
|
||||
<artifactId>osgi-intro</artifactId>
|
||||
<groupId>com.baeldung</groupId>
|
||||
<version>1.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<!-- Please, note this is not the usual 'jar'. -->
|
||||
<packaging>bundle</packaging>
|
||||
|
||||
<artifactId>osgi-intro-sample-activator</artifactId>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.osgi</groupId>
|
||||
<artifactId>org.osgi.core</artifactId>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.felix</groupId>
|
||||
<artifactId>maven-bundle-plugin</artifactId>
|
||||
<extensions>true</extensions>
|
||||
<configuration>
|
||||
<instructions>
|
||||
<Bundle-SymbolicName>${project.groupId}.${project.artifactId}</Bundle-SymbolicName>
|
||||
<Bundle-Name>${project.artifactId}</Bundle-Name>
|
||||
<Bundle-Version>${project.version}</Bundle-Version>
|
||||
|
||||
<!-- Qualified name of the class that exposes the activator iface. -->
|
||||
<Bundle-Activator>com.baeldung.osgi.sample.activator.HelloWorld</Bundle-Activator>
|
||||
|
||||
<!-- One important thing to note:
|
||||
since you are not exporting the package "com.baeldung.osgi.sample.activator",
|
||||
you should at least add it to the Private-Package instruction.
|
||||
Otherwise, the classes inside the package will not be copied to your bundle,
|
||||
as the default value of this instruction is empty. -->
|
||||
|
||||
<Private-Package>com.baeldung.osgi.sample.activator</Private-Package>
|
||||
|
||||
</instructions>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
|
||||
</project>
|
|
@ -0,0 +1,16 @@
|
|||
package com.baeldung.osgi.sample.activator;
|
||||
|
||||
import org.osgi.framework.BundleActivator;
|
||||
import org.osgi.framework.BundleContext;
|
||||
|
||||
public class HelloWorld implements BundleActivator {
|
||||
|
||||
public void start(BundleContext ctx) {
|
||||
System.out.println("Hello World.");
|
||||
}
|
||||
|
||||
public void stop(BundleContext bundleContext) {
|
||||
System.out.println("Goodbye World.");
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,49 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<parent>
|
||||
<artifactId>osgi-intro</artifactId>
|
||||
<groupId>com.baeldung</groupId>
|
||||
<version>1.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<!-- mvn:com.baeldung/osgi-intro-sample-client/1.0-SNAPSHOT -->
|
||||
<artifactId>osgi-intro-sample-client</artifactId>
|
||||
|
||||
<packaging>bundle</packaging>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>com.baeldung</groupId>
|
||||
<artifactId>osgi-intro-sample-service</artifactId>
|
||||
<version>1.0-SNAPSHOT</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.osgi</groupId>
|
||||
<artifactId>org.osgi.core</artifactId>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.felix</groupId>
|
||||
<artifactId>maven-bundle-plugin</artifactId>
|
||||
<configuration>
|
||||
<instructions>
|
||||
<Bundle-SymbolicName>${project.groupId}.${project.artifactId}</Bundle-SymbolicName>
|
||||
<Bundle-Name>${project.artifactId}</Bundle-Name>
|
||||
<Bundle-Version>${project.version}</Bundle-Version>
|
||||
<Bundle-Activator>com.baeldung.osgi.sample.client.Client</Bundle-Activator>
|
||||
|
||||
<Private-Package>com.baeldung.osgi.sample.client</Private-Package>
|
||||
|
||||
</instructions>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
|
||||
</project>
|
|
@ -0,0 +1,44 @@
|
|||
package com.baeldung.osgi.sample.client;
|
||||
|
||||
import com.baeldung.osgi.sample.service.definition.Greeter;
|
||||
import org.osgi.framework.*;
|
||||
|
||||
public class Client implements BundleActivator, ServiceListener {
|
||||
|
||||
private BundleContext ctx;
|
||||
private ServiceReference serviceReference;
|
||||
|
||||
public void start(BundleContext ctx) {
|
||||
this.ctx = ctx;
|
||||
try {
|
||||
ctx.addServiceListener(this, "(objectclass=" + Greeter.class.getName() + ")");
|
||||
} catch (InvalidSyntaxException ise) {
|
||||
ise.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
public void stop(BundleContext bundleContext) {
|
||||
if (serviceReference != null) {
|
||||
ctx.ungetService(serviceReference);
|
||||
}
|
||||
this.ctx = null;
|
||||
}
|
||||
|
||||
public void serviceChanged(ServiceEvent serviceEvent) {
|
||||
int type = serviceEvent.getType();
|
||||
switch (type) {
|
||||
case (ServiceEvent.REGISTERED):
|
||||
System.out.println("Notification of service registered.");
|
||||
serviceReference = serviceEvent.getServiceReference();
|
||||
Greeter service = (Greeter) (ctx.getService(serviceReference));
|
||||
System.out.println(service.sayHiTo("John"));
|
||||
break;
|
||||
case (ServiceEvent.UNREGISTERING):
|
||||
System.out.println("Notification of service unregistered.");
|
||||
ctx.ungetService(serviceEvent.getServiceReference());
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,46 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
|
||||
<!-- mvn:com.baeldung/osgi-intro-sample-service/1.0-SNAPSHOT -->
|
||||
<parent>
|
||||
<artifactId>osgi-intro</artifactId>
|
||||
<groupId>com.baeldung</groupId>
|
||||
<version>1.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<artifactId>osgi-intro-sample-service</artifactId>
|
||||
|
||||
<!-- Please, note this is not the usual 'jar'. -->
|
||||
<packaging>bundle</packaging>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.osgi</groupId>
|
||||
<artifactId>org.osgi.core</artifactId>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.felix</groupId>
|
||||
<artifactId>maven-bundle-plugin</artifactId>
|
||||
<extensions>true</extensions>
|
||||
<configuration>
|
||||
<instructions>
|
||||
<Bundle-SymbolicName>${project.groupId}.${project.artifactId}</Bundle-SymbolicName>
|
||||
<Bundle-Name>${project.artifactId}</Bundle-Name>
|
||||
<Bundle-Version>${project.version}</Bundle-Version>
|
||||
<Bundle-Activator>com.baeldung.osgi.sample.service.implementation.GreeterImpl</Bundle-Activator>
|
||||
<Private-Package>com.baeldung.osgi.sample.service.implementation</Private-Package>
|
||||
<Export-Package>com.baeldung.osgi.sample.service.definition</Export-Package>
|
||||
</instructions>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
|
||||
</project>
|
|
@ -0,0 +1,7 @@
|
|||
package com.baeldung.osgi.sample.service.definition;
|
||||
|
||||
public interface Greeter {
|
||||
|
||||
public String sayHiTo(String name);
|
||||
|
||||
}
|
|
@ -0,0 +1,30 @@
|
|||
package com.baeldung.osgi.sample.service.implementation;
|
||||
|
||||
import com.baeldung.osgi.sample.service.definition.Greeter;
|
||||
import org.osgi.framework.BundleActivator;
|
||||
import org.osgi.framework.BundleContext;
|
||||
import org.osgi.framework.ServiceReference;
|
||||
import org.osgi.framework.ServiceRegistration;
|
||||
|
||||
import java.util.Hashtable;
|
||||
|
||||
public class GreeterImpl implements Greeter, BundleActivator {
|
||||
|
||||
private ServiceReference<Greeter> reference;
|
||||
private ServiceRegistration<Greeter> registration;
|
||||
|
||||
@Override public String sayHiTo(String name) {
|
||||
return "Hello " + name;
|
||||
}
|
||||
|
||||
@Override public void start(BundleContext context) throws Exception {
|
||||
System.out.println("Registering service.");
|
||||
registration = context.registerService(Greeter.class, new GreeterImpl(), new Hashtable<String, String>());
|
||||
reference = registration.getReference();
|
||||
}
|
||||
|
||||
@Override public void stop(BundleContext context) throws Exception {
|
||||
System.out.println("Unregistering service.");
|
||||
registration.unregister();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,87 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<artifactId>osgi-intro</artifactId>
|
||||
<packaging>pom</packaging>
|
||||
<version>1.0-SNAPSHOT</version>
|
||||
<modules>
|
||||
<module>osgi-intro-sample-activator</module>
|
||||
<module>osgi-intro-sample-service</module>
|
||||
<module>osgi-intro-sample-client</module>
|
||||
</modules>
|
||||
|
||||
<parent>
|
||||
<groupId>com.baeldung</groupId>
|
||||
<artifactId>parent-modules</artifactId>
|
||||
<version>1.0.0-SNAPSHOT</version>
|
||||
<relativePath>..</relativePath>
|
||||
</parent>
|
||||
|
||||
<dependencyManagement>
|
||||
<dependencies>
|
||||
|
||||
<dependency>
|
||||
<groupId>${project.groupId}</groupId>
|
||||
<artifactId>osgi-intro-client</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>${project.groupId}</groupId>
|
||||
<artifactId>osgi-intro-service</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>${project.groupId}</groupId>
|
||||
<artifactId>osgi-intro-gxyz</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>${project.groupId}</groupId>
|
||||
<artifactId>osgi-intro-mapquest</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.squareup.okhttp3</groupId>
|
||||
<artifactId>okhttp</artifactId>
|
||||
<version>3.9.0</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>javax.json</groupId>
|
||||
<artifactId>javax.json-api</artifactId>
|
||||
<version>1.1</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.glassfish</groupId>
|
||||
<artifactId>javax.json</artifactId>
|
||||
<version>1.1</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.osgi</groupId>
|
||||
<artifactId>org.osgi.core</artifactId>
|
||||
<version>5.0.0</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</dependencyManagement>
|
||||
|
||||
<build>
|
||||
<pluginManagement>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.felix</groupId>
|
||||
<artifactId>maven-bundle-plugin</artifactId>
|
||||
<version>1.4.0</version>
|
||||
<extensions>true</extensions>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</pluginManagement>
|
||||
</build>
|
||||
|
||||
</project>
|
24
pom.xml
24
pom.xml
|
@ -62,10 +62,10 @@
|
|||
<module>feign</module>
|
||||
<module>flyway</module>
|
||||
|
||||
<!-- <module>gatling</module> --> <!-- not meant to run as part of the standard build -->
|
||||
<!-- <module>testing-modules/gatling</module> --> <!-- not meant to run as part of the standard build -->
|
||||
|
||||
<module>geotools</module>
|
||||
<module>groovy-spock</module>
|
||||
<module>testing-modules/groovy-spock</module>
|
||||
<module>gson</module>
|
||||
<module>guava</module>
|
||||
<module>guava18</module>
|
||||
|
@ -98,7 +98,7 @@
|
|||
<module>json-path</module>
|
||||
<module>json</module>
|
||||
<module>jsoup</module>
|
||||
<module>junit5</module>
|
||||
<module>testing-modules/junit-5</module>
|
||||
<module>jws</module>
|
||||
|
||||
<module>libraries</module>
|
||||
|
@ -112,9 +112,9 @@
|
|||
<module>mapstruct</module>
|
||||
<module>metrics</module>
|
||||
<module>mesos-marathon</module>
|
||||
<module>mockito</module>
|
||||
<module>mockito2</module>
|
||||
<module>mocks</module>
|
||||
<module>testing-modules/mockito</module>
|
||||
<module>testing-modules/mockito-2</module>
|
||||
<module>testing-modules/mocks</module>
|
||||
<module>mustache</module>
|
||||
<module>noexception</module>
|
||||
|
||||
|
@ -129,13 +129,13 @@
|
|||
<!-- <module>raml</module> -->
|
||||
<module>reactor-core</module>
|
||||
<module>persistence-modules/redis</module>
|
||||
<module>rest-assured</module>
|
||||
<module>rest-testing</module>
|
||||
<module>testing-modules/rest-assured</module>
|
||||
<module>testing-modules/rest-testing</module>
|
||||
<module>resteasy</module>
|
||||
<module>rxjava</module>
|
||||
<module>spring-swagger-codegen</module>
|
||||
|
||||
<module>selenium-junit-testng</module>
|
||||
<module>testing-modules/selenium-junit-testng</module>
|
||||
<module>persistence-modules/solr</module>
|
||||
<module>spark-java</module>
|
||||
<!-- <module>spring-5</module>-->
|
||||
|
@ -235,8 +235,8 @@
|
|||
<module>spring-rest-embedded-tomcat</module>
|
||||
|
||||
|
||||
<module>testing</module>
|
||||
<module>testng</module>
|
||||
<module>testing-modules/testing</module>
|
||||
<module>testing-modules/testng</module>
|
||||
|
||||
<module>video-tutorials</module>
|
||||
|
||||
|
@ -254,7 +254,7 @@
|
|||
<module>drools</module>
|
||||
<module>persistence-modules/liquibase</module>
|
||||
<module>spring-boot-property-exp</module>
|
||||
<module>mockserver</module>
|
||||
<module>testing-modules/mockserver</module>
|
||||
<module>undertow</module>
|
||||
<module>vertx-and-rxjava</module>
|
||||
<module>saas</module>
|
||||
|
|
|
@ -0,0 +1,33 @@
|
|||
package org.baeldung.sqlfiles;
|
||||
|
||||
import static javax.persistence.GenerationType.IDENTITY;
|
||||
|
||||
import javax.persistence.Column;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.GeneratedValue;
|
||||
import javax.persistence.Id;
|
||||
|
||||
@Entity
|
||||
public class Country {
|
||||
|
||||
@Id
|
||||
@GeneratedValue(strategy = IDENTITY)
|
||||
private Integer id;
|
||||
|
||||
@Column(nullable = false)
|
||||
private String name;
|
||||
|
||||
public Integer getId() {
|
||||
return id;
|
||||
}
|
||||
public void setId(Integer id) {
|
||||
this.id = id;
|
||||
}
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,5 @@
|
|||
INSERT INTO country (name) VALUES ('India');
|
||||
INSERT INTO country (name) VALUES ('Brazil');
|
||||
INSERT INTO country (name) VALUES ('USA');
|
||||
INSERT INTO country (name) VALUES ('Italy');
|
||||
COMMIT;
|
|
@ -0,0 +1,5 @@
|
|||
CREATE TABLE country (
|
||||
id INTEGER NOT NULL AUTO_INCREMENT,
|
||||
name VARCHAR(128) NOT NULL,
|
||||
PRIMARY KEY (id)
|
||||
);
|
|
@ -0,0 +1 @@
|
|||
spring.jpa.hibernate.ddl-auto=none
|
|
@ -122,6 +122,25 @@
|
|||
<artifactId>jstl-api</artifactId>
|
||||
<version>${jstl.version}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.springframework.security</groupId>
|
||||
<artifactId>spring-security-acl</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.security</groupId>
|
||||
<artifactId>spring-security-config</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-context-support</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>net.sf.ehcache</groupId>
|
||||
<artifactId>ehcache-core</artifactId>
|
||||
<version>2.6.11</version>
|
||||
<type>jar</type>
|
||||
</dependency>
|
||||
|
||||
</dependencies>
|
||||
|
||||
|
|
|
@ -0,0 +1,80 @@
|
|||
package org.baeldung.acl.config;
|
||||
|
||||
import javax.sql.DataSource;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
|
||||
import org.springframework.cache.ehcache.EhCacheFactoryBean;
|
||||
import org.springframework.cache.ehcache.EhCacheManagerFactoryBean;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.security.access.expression.method.DefaultMethodSecurityExpressionHandler;
|
||||
import org.springframework.security.access.expression.method.MethodSecurityExpressionHandler;
|
||||
import org.springframework.security.acls.AclPermissionCacheOptimizer;
|
||||
import org.springframework.security.acls.AclPermissionEvaluator;
|
||||
import org.springframework.security.acls.domain.AclAuthorizationStrategy;
|
||||
import org.springframework.security.acls.domain.AclAuthorizationStrategyImpl;
|
||||
import org.springframework.security.acls.domain.ConsoleAuditLogger;
|
||||
import org.springframework.security.acls.domain.DefaultPermissionGrantingStrategy;
|
||||
import org.springframework.security.acls.domain.EhCacheBasedAclCache;
|
||||
import org.springframework.security.acls.jdbc.BasicLookupStrategy;
|
||||
import org.springframework.security.acls.jdbc.JdbcMutableAclService;
|
||||
import org.springframework.security.acls.jdbc.LookupStrategy;
|
||||
import org.springframework.security.acls.model.PermissionGrantingStrategy;
|
||||
import org.springframework.security.core.authority.SimpleGrantedAuthority;
|
||||
|
||||
@Configuration
|
||||
@EnableAutoConfiguration
|
||||
public class ACLContext {
|
||||
|
||||
@Autowired
|
||||
DataSource dataSource;
|
||||
|
||||
@Bean
|
||||
public EhCacheBasedAclCache aclCache() {
|
||||
return new EhCacheBasedAclCache(aclEhCacheFactoryBean().getObject(), permissionGrantingStrategy(), aclAuthorizationStrategy());
|
||||
}
|
||||
|
||||
@Bean
|
||||
public EhCacheFactoryBean aclEhCacheFactoryBean() {
|
||||
EhCacheFactoryBean ehCacheFactoryBean = new EhCacheFactoryBean();
|
||||
ehCacheFactoryBean.setCacheManager(aclCacheManager().getObject());
|
||||
ehCacheFactoryBean.setCacheName("aclCache");
|
||||
return ehCacheFactoryBean;
|
||||
}
|
||||
|
||||
@Bean
|
||||
public EhCacheManagerFactoryBean aclCacheManager() {
|
||||
return new EhCacheManagerFactoryBean();
|
||||
}
|
||||
|
||||
@Bean
|
||||
public PermissionGrantingStrategy permissionGrantingStrategy() {
|
||||
return new DefaultPermissionGrantingStrategy(new ConsoleAuditLogger());
|
||||
}
|
||||
|
||||
@Bean
|
||||
public AclAuthorizationStrategy aclAuthorizationStrategy() {
|
||||
return new AclAuthorizationStrategyImpl(new SimpleGrantedAuthority("ROLE_ADMIN"));
|
||||
}
|
||||
|
||||
@Bean
|
||||
public MethodSecurityExpressionHandler defaultMethodSecurityExpressionHandler() {
|
||||
DefaultMethodSecurityExpressionHandler expressionHandler = new DefaultMethodSecurityExpressionHandler();
|
||||
AclPermissionEvaluator permissionEvaluator = new AclPermissionEvaluator(aclService());
|
||||
expressionHandler.setPermissionEvaluator(permissionEvaluator);
|
||||
expressionHandler.setPermissionCacheOptimizer(new AclPermissionCacheOptimizer(aclService()));
|
||||
return expressionHandler;
|
||||
}
|
||||
|
||||
@Bean
|
||||
public LookupStrategy lookupStrategy() {
|
||||
return new BasicLookupStrategy(dataSource, aclCache(), aclAuthorizationStrategy(), new ConsoleAuditLogger());
|
||||
}
|
||||
|
||||
@Bean
|
||||
public JdbcMutableAclService aclService() {
|
||||
return new JdbcMutableAclService(dataSource, lookupStrategy(), aclCache());
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,21 @@
|
|||
package org.baeldung.acl.config;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.security.access.expression.method.MethodSecurityExpressionHandler;
|
||||
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
|
||||
import org.springframework.security.config.annotation.method.configuration.GlobalMethodSecurityConfiguration;
|
||||
|
||||
@Configuration
|
||||
@EnableGlobalMethodSecurity(prePostEnabled = true, securedEnabled = true)
|
||||
public class AclMethodSecurityConfiguration extends GlobalMethodSecurityConfiguration {
|
||||
|
||||
@Autowired
|
||||
MethodSecurityExpressionHandler defaultMethodSecurityExpressionHandler;
|
||||
|
||||
@Override
|
||||
protected MethodSecurityExpressionHandler createExpressionHandler() {
|
||||
return defaultMethodSecurityExpressionHandler;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,16 @@
|
|||
package org.baeldung.acl.config;
|
||||
|
||||
import org.springframework.boot.autoconfigure.domain.EntityScan;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.PropertySource;
|
||||
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
|
||||
import org.springframework.transaction.annotation.EnableTransactionManagement;
|
||||
|
||||
@Configuration
|
||||
@EnableTransactionManagement
|
||||
@EnableJpaRepositories(basePackages = "org.baeldung.acl.persistence.dao")
|
||||
@PropertySource("classpath:org.baeldung.acl.datasource.properties")
|
||||
@EntityScan(basePackages={ "org.baeldung.acl.persistence.entity" })
|
||||
public class JPAPersistenceConfig {
|
||||
|
||||
}
|
|
@ -0,0 +1,24 @@
|
|||
package org.baeldung.acl.persistence.dao;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.baeldung.acl.persistence.entity.NoticeMessage;
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
import org.springframework.data.repository.query.Param;
|
||||
import org.springframework.security.access.prepost.PostAuthorize;
|
||||
import org.springframework.security.access.prepost.PostFilter;
|
||||
import org.springframework.security.access.prepost.PreAuthorize;
|
||||
|
||||
public interface NoticeMessageRepository extends JpaRepository<NoticeMessage, Long>{
|
||||
|
||||
@PostFilter("hasPermission(filterObject, 'READ')")
|
||||
List<NoticeMessage> findAll();
|
||||
|
||||
@PostAuthorize("hasPermission(returnObject, 'READ')")
|
||||
NoticeMessage findById(Integer id);
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@PreAuthorize("hasPermission(#noticeMessage, 'WRITE')")
|
||||
NoticeMessage save(@Param("noticeMessage")NoticeMessage noticeMessage);
|
||||
|
||||
}
|
|
@ -0,0 +1,29 @@
|
|||
package org.baeldung.acl.persistence.entity;
|
||||
|
||||
import javax.persistence.Column;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.Id;
|
||||
import javax.persistence.Table;
|
||||
|
||||
@Entity
|
||||
@Table(name="system_message")
|
||||
public class NoticeMessage {
|
||||
|
||||
@Id
|
||||
@Column
|
||||
private Integer id;
|
||||
@Column
|
||||
private String content;
|
||||
public Integer getId() {
|
||||
return id;
|
||||
}
|
||||
public void setId(Integer id) {
|
||||
this.id = id;
|
||||
}
|
||||
public String getContent() {
|
||||
return content;
|
||||
}
|
||||
public void setContent(String content) {
|
||||
this.content = content;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,28 @@
|
|||
INSERT INTO system_message(id,content) VALUES (1,'First Level Message');
|
||||
INSERT INTO system_message(id,content) VALUES (2,'Second Level Message');
|
||||
INSERT INTO system_message(id,content) VALUES (3,'Third Level Message');
|
||||
|
||||
INSERT INTO acl_class (id, class) VALUES
|
||||
(1, 'org.baeldung.acl.persistence.entity.NoticeMessage');
|
||||
|
||||
INSERT INTO acl_sid (id, principal, sid) VALUES
|
||||
(1, 1, 'manager'),
|
||||
(2, 1, 'hr'),
|
||||
(3, 1, 'admin'),
|
||||
(4, 0, 'ROLE_EDITOR');
|
||||
|
||||
INSERT INTO acl_object_identity (id, object_id_class, object_id_identity, parent_object, owner_sid, entries_inheriting) VALUES
|
||||
(1, 1, 1, NULL, 3, 0),
|
||||
(2, 1, 2, NULL, 3, 0),
|
||||
(3, 1, 3, NULL, 3, 0)
|
||||
;
|
||||
|
||||
INSERT INTO acl_entry (id, acl_object_identity, ace_order, sid, mask, granting, audit_success, audit_failure) VALUES
|
||||
(1, 1, 1, 1, 1, 1, 1, 1),
|
||||
(2, 1, 2, 1, 2, 1, 1, 1),
|
||||
(3, 1, 3, 4, 1, 1, 1, 1),
|
||||
(4, 2, 1, 2, 1, 1, 1, 1),
|
||||
(5, 2, 2, 4, 1, 1, 1, 1),
|
||||
(6, 3, 1, 4, 1, 1, 1, 1),
|
||||
(7, 3, 2, 4, 2, 1, 1, 1)
|
||||
;
|
|
@ -0,0 +1,58 @@
|
|||
create table system_message (id integer not null, content varchar(255), primary key (id));
|
||||
|
||||
CREATE TABLE IF NOT EXISTS acl_sid (
|
||||
id bigint(20) NOT NULL AUTO_INCREMENT,
|
||||
principal tinyint(1) NOT NULL,
|
||||
sid varchar(100) NOT NULL,
|
||||
PRIMARY KEY (id),
|
||||
UNIQUE KEY unique_uk_1 (sid,principal)
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS acl_class (
|
||||
id bigint(20) NOT NULL AUTO_INCREMENT,
|
||||
class varchar(255) NOT NULL,
|
||||
PRIMARY KEY (id),
|
||||
UNIQUE KEY unique_uk_2 (class)
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS acl_entry (
|
||||
id bigint(20) NOT NULL AUTO_INCREMENT,
|
||||
acl_object_identity bigint(20) NOT NULL,
|
||||
ace_order int(11) NOT NULL,
|
||||
sid bigint(20) NOT NULL,
|
||||
mask int(11) NOT NULL,
|
||||
granting tinyint(1) NOT NULL,
|
||||
audit_success tinyint(1) NOT NULL,
|
||||
audit_failure tinyint(1) NOT NULL,
|
||||
PRIMARY KEY (id),
|
||||
UNIQUE KEY unique_uk_4 (acl_object_identity,ace_order)
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS acl_object_identity (
|
||||
id bigint(20) NOT NULL AUTO_INCREMENT,
|
||||
object_id_class bigint(20) NOT NULL,
|
||||
object_id_identity bigint(20) NOT NULL,
|
||||
parent_object bigint(20) DEFAULT NULL,
|
||||
owner_sid bigint(20) DEFAULT NULL,
|
||||
entries_inheriting tinyint(1) NOT NULL,
|
||||
PRIMARY KEY (id),
|
||||
UNIQUE KEY unique_uk_3 (object_id_class,object_id_identity)
|
||||
);
|
||||
|
||||
ALTER TABLE acl_entry
|
||||
ADD FOREIGN KEY (acl_object_identity) REFERENCES acl_object_identity(id);
|
||||
|
||||
ALTER TABLE acl_entry
|
||||
ADD FOREIGN KEY (sid) REFERENCES acl_sid(id);
|
||||
|
||||
--
|
||||
-- Constraints for table acl_object_identity
|
||||
--
|
||||
ALTER TABLE acl_object_identity
|
||||
ADD FOREIGN KEY (parent_object) REFERENCES acl_object_identity (id);
|
||||
|
||||
ALTER TABLE acl_object_identity
|
||||
ADD FOREIGN KEY (object_id_class) REFERENCES acl_class (id);
|
||||
|
||||
ALTER TABLE acl_object_identity
|
||||
ADD FOREIGN KEY (owner_sid) REFERENCES acl_sid (id);
|
|
@ -0,0 +1,12 @@
|
|||
spring.datasource.url=jdbc:h2:mem:testdb;DB_CLOSE_ON_EXIT=FALSE
|
||||
spring.datasource.username=sa
|
||||
spring.datasource.password=
|
||||
spring.datasource.driverClassName=org.h2.Driver
|
||||
spring.jpa.hibernate.ddl-auto=update
|
||||
spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.H2Dialect
|
||||
|
||||
spring.h2.console.path=/myconsole
|
||||
spring.h2.console.enabled=true
|
||||
spring.datasource.initialize=true
|
||||
spring.datasource.schema=classpath:acl-schema.sql
|
||||
spring.datasource.data=classpath:acl-data.sql
|
|
@ -0,0 +1,119 @@
|
|||
package org.baeldung.acl;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.baeldung.acl.persistence.dao.NoticeMessageRepository;
|
||||
import org.baeldung.acl.persistence.entity.NoticeMessage;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.annotation.ComponentScan;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.security.access.AccessDeniedException;
|
||||
import org.springframework.security.test.context.support.WithMockUser;
|
||||
import org.springframework.security.test.context.support.WithSecurityContextTestExecutionListener;
|
||||
import org.springframework.test.context.ContextConfiguration;
|
||||
import org.springframework.test.context.TestExecutionListeners;
|
||||
import org.springframework.test.context.junit4.AbstractJUnit4SpringContextTests;
|
||||
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
|
||||
import org.springframework.test.context.support.DependencyInjectionTestExecutionListener;
|
||||
import org.springframework.test.context.support.DirtiesContextTestExecutionListener;
|
||||
import org.springframework.test.context.transaction.TransactionalTestExecutionListener;
|
||||
import org.springframework.test.context.web.ServletTestExecutionListener;
|
||||
|
||||
@RunWith(SpringJUnit4ClassRunner.class)
|
||||
@ContextConfiguration
|
||||
@TestExecutionListeners(listeners={ServletTestExecutionListener.class,
|
||||
DependencyInjectionTestExecutionListener.class,
|
||||
DirtiesContextTestExecutionListener.class,
|
||||
TransactionalTestExecutionListener.class,
|
||||
WithSecurityContextTestExecutionListener.class})
|
||||
public class SpringAclTest extends AbstractJUnit4SpringContextTests{
|
||||
|
||||
private static Integer FIRST_MESSAGE_ID = 1;
|
||||
private static Integer SECOND_MESSAGE_ID = 2;
|
||||
private static Integer THIRD_MESSAGE_ID = 3;
|
||||
private static String EDITTED_CONTENT = "EDITED";
|
||||
|
||||
@Configuration
|
||||
@ComponentScan("org.baeldung.acl.*")
|
||||
public static class SpringConfig {
|
||||
|
||||
}
|
||||
|
||||
@Autowired
|
||||
NoticeMessageRepository repo;
|
||||
|
||||
@Test
|
||||
@WithMockUser(username="manager")
|
||||
public void givenUsernameManager_whenFindAllMessage_thenReturnFirstMessage(){
|
||||
List<NoticeMessage> details = repo.findAll();
|
||||
assertNotNull(details);
|
||||
assertEquals(1,details.size());
|
||||
assertEquals(FIRST_MESSAGE_ID,details.get(0).getId());
|
||||
}
|
||||
|
||||
@Test
|
||||
@WithMockUser(username="manager")
|
||||
public void givenUsernameManager_whenFindFirstMessageByIdAndUpdateFirstMessageContent_thenOK(){
|
||||
NoticeMessage firstMessage = repo.findById(FIRST_MESSAGE_ID);
|
||||
assertNotNull(firstMessage);
|
||||
assertEquals(FIRST_MESSAGE_ID,firstMessage.getId());
|
||||
|
||||
firstMessage.setContent(EDITTED_CONTENT);
|
||||
repo.save(firstMessage);
|
||||
|
||||
NoticeMessage editedFirstMessage = repo.findById(FIRST_MESSAGE_ID);
|
||||
assertNotNull(editedFirstMessage);
|
||||
assertEquals(FIRST_MESSAGE_ID,editedFirstMessage.getId());
|
||||
assertEquals(EDITTED_CONTENT,editedFirstMessage.getContent());
|
||||
}
|
||||
|
||||
@Test
|
||||
@WithMockUser(username="hr")
|
||||
public void givenUsernameHr_whenFindMessageById2_thenOK(){
|
||||
NoticeMessage secondMessage = repo.findById(SECOND_MESSAGE_ID);
|
||||
assertNotNull(secondMessage);
|
||||
assertEquals(SECOND_MESSAGE_ID,secondMessage.getId());
|
||||
}
|
||||
|
||||
@Test(expected=AccessDeniedException.class)
|
||||
@WithMockUser(username="hr")
|
||||
public void givenUsernameHr_whenUpdateMessageWithId2_thenFail(){
|
||||
NoticeMessage secondMessage = new NoticeMessage();
|
||||
secondMessage.setId(SECOND_MESSAGE_ID);
|
||||
secondMessage.setContent(EDITTED_CONTENT);
|
||||
repo.save(secondMessage);
|
||||
}
|
||||
|
||||
@Test
|
||||
@WithMockUser(roles={"EDITOR"})
|
||||
public void givenRoleEditor_whenFindAllMessage_thenReturnThreeMessage(){
|
||||
List<NoticeMessage> details = repo.findAll();
|
||||
assertNotNull(details);
|
||||
assertEquals(3,details.size());
|
||||
}
|
||||
|
||||
@Test
|
||||
@WithMockUser(roles={"EDITOR"})
|
||||
public void givenRoleEditor_whenUpdateThirdMessage_thenOK(){
|
||||
NoticeMessage thirdMessage = new NoticeMessage();
|
||||
thirdMessage.setId(THIRD_MESSAGE_ID);
|
||||
thirdMessage.setContent(EDITTED_CONTENT);
|
||||
repo.save(thirdMessage);
|
||||
}
|
||||
|
||||
@Test(expected=AccessDeniedException.class)
|
||||
@WithMockUser(roles={"EDITOR"})
|
||||
public void givenRoleEditor_whenFindFirstMessageByIdAndUpdateFirstMessageContent_thenFail(){
|
||||
NoticeMessage firstMessage = repo.findById(FIRST_MESSAGE_ID);
|
||||
assertNotNull(firstMessage);
|
||||
assertEquals(FIRST_MESSAGE_ID,firstMessage.getId());
|
||||
firstMessage.setContent(EDITTED_CONTENT);
|
||||
repo.save(firstMessage);
|
||||
}
|
||||
}
|
||||
|
|
@ -17,6 +17,7 @@
|
|||
<groupId>com.baeldung</groupId>
|
||||
<artifactId>parent-modules</artifactId>
|
||||
<version>1.0.0-SNAPSHOT</version>
|
||||
<relativePath>../</relativePath>
|
||||
</parent>
|
||||
|
||||
<build>
|
|
@ -4,16 +4,17 @@
|
|||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<!-- NOT NEEDED - JSP <groupId>com.baeldung</groupId>-->
|
||||
<artifactId>junit5</artifactId>
|
||||
<artifactId>junit-5</artifactId>
|
||||
<version>1.0-SNAPSHOT</version>
|
||||
|
||||
<name>junit5</name>
|
||||
<name>junit-5</name>
|
||||
<description>Intro to JUnit 5</description>
|
||||
|
||||
<parent>
|
||||
<groupId>com.baeldung</groupId>
|
||||
<artifactId>parent-modules</artifactId>
|
||||
<version>1.0.0-SNAPSHOT</version>
|
||||
<relativePath>../</relativePath>
|
||||
</parent>
|
||||
|
||||
<properties>
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue