Merge remote-tracking branch 'upstream/master'

This commit is contained in:
gschambial 2017-11-13 10:46:30 +05:30
commit 3319b28b9c
280 changed files with 1749 additions and 41 deletions

View File

@ -216,6 +216,13 @@
<artifactId>spring-web</artifactId> <artifactId>spring-web</artifactId>
<version>4.3.4.RELEASE</version> <version>4.3.4.RELEASE</version>
</dependency> </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> </dependencies>
<build> <build>

View File

@ -0,0 +1,9 @@
package com.baeldung.javac;
import java.lang.annotation.*;
@Documented
@Retention(RetentionPolicy.CLASS)
@Target({ElementType.PARAMETER})
public @interface Positive {
}

View File

@ -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))));
}
}

View File

@ -0,0 +1 @@
com.baeldung.javac.SampleJavacPlugin

View File

@ -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);
}
}

View File

@ -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();
}
}

View File

@ -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;
}
}

View File

@ -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;
}
}

View File

@ -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();
}
}

View File

@ -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();
}
}
}

View File

@ -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);
}
}

View File

@ -16,32 +16,29 @@ import wildfly.beans.UserBeanLocal;
* Servlet implementation class TestEJBServlet * Servlet implementation class TestEJBServlet
*/ */
public class TestEJBServlet extends HttpServlet { public class TestEJBServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
@EJB @EJB
private UserBeanLocal userBean; private UserBeanLocal userBean;
protected void doGet(HttpServletRequest request, HttpServletResponse response) protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
throws ServletException, IOException { List<User> users = userBean.getUsers();
List<User> users = userBean.getUsers();
PrintWriter out = response.getWriter(); PrintWriter out = response.getWriter();
out.println("<html>"); out.println("<html>");
out.println("<head><title>Users</title></head>"); out.println("<head><title>Users</title></head>");
out.println("<body>"); out.println("<body>");
out.println("<center><h1>List of users:</h1>"); out.println("<center><h1>List of users:</h1>");
out.println("<table border=\"1\" align=\"center\" style=\"width:50%\">"); out.println("<table border=\"1\" align=\"center\" style=\"width:50%\">");
for (User user : users) { for (User user : users) {
out.println("<tr>"); out.println("<tr>");
out.print("<td>" + user.getUsername() + "</td>"); out.print("<td>" + user.getUsername() + "</td>");
out.print("<td>" + user.getEmail() + "</td>"); out.print("<td>" + user.getEmail() + "</td>");
out.println("</tr>"); out.println("</tr>");
} }
} }
protected void doPost(HttpServletRequest request, HttpServletResponse response) protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
throws ServletException, IOException { doGet(request, response);
doGet(request, response); }
}
} }

View File

@ -1,3 +1,4 @@
## Relevant articles: ## Relevant articles:
- [Dynamic Mapping with Hibernate](http://www.baeldung.com/hibernate-dynamic-mapping) - [Dynamic Mapping with Hibernate](http://www.baeldung.com/hibernate-dynamic-mapping)
- [An Overview of Identifiers in Hibernate](http://www.baeldung.com/hibernate-identifiers)

View File

@ -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>

View File

@ -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.");
}
}

View File

@ -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>

View File

@ -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;
}
}
}

View File

@ -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>

View File

@ -0,0 +1,7 @@
package com.baeldung.osgi.sample.service.definition;
public interface Greeter {
public String sayHiTo(String name);
}

View File

@ -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();
}
}

87
osgi/intro/pom.xml Normal file
View File

@ -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>

91
osgi/intro/readme.md Normal file
View File

@ -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 = =

View File

@ -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>

View File

@ -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.");
}
}

View File

@ -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>

View File

@ -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;
}
}
}

View File

@ -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>

View File

@ -0,0 +1,7 @@
package com.baeldung.osgi.sample.service.definition;
public interface Greeter {
public String sayHiTo(String name);
}

View File

@ -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();
}
}

87
osgi/pom.xml Normal file
View File

@ -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
View File

@ -62,10 +62,10 @@
<module>feign</module> <module>feign</module>
<module>flyway</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>geotools</module>
<module>groovy-spock</module> <module>testing-modules/groovy-spock</module>
<module>gson</module> <module>gson</module>
<module>guava</module> <module>guava</module>
<module>guava18</module> <module>guava18</module>
@ -98,7 +98,7 @@
<module>json-path</module> <module>json-path</module>
<module>json</module> <module>json</module>
<module>jsoup</module> <module>jsoup</module>
<module>junit5</module> <module>testing-modules/junit-5</module>
<module>jws</module> <module>jws</module>
<module>libraries</module> <module>libraries</module>
@ -112,9 +112,9 @@
<module>mapstruct</module> <module>mapstruct</module>
<module>metrics</module> <module>metrics</module>
<module>mesos-marathon</module> <module>mesos-marathon</module>
<module>mockito</module> <module>testing-modules/mockito</module>
<module>mockito2</module> <module>testing-modules/mockito-2</module>
<module>mocks</module> <module>testing-modules/mocks</module>
<module>mustache</module> <module>mustache</module>
<module>noexception</module> <module>noexception</module>
@ -129,13 +129,13 @@
<!-- <module>raml</module> --> <!-- <module>raml</module> -->
<module>reactor-core</module> <module>reactor-core</module>
<module>persistence-modules/redis</module> <module>persistence-modules/redis</module>
<module>rest-assured</module> <module>testing-modules/rest-assured</module>
<module>rest-testing</module> <module>testing-modules/rest-testing</module>
<module>resteasy</module> <module>resteasy</module>
<module>rxjava</module> <module>rxjava</module>
<module>spring-swagger-codegen</module> <module>spring-swagger-codegen</module>
<module>selenium-junit-testng</module> <module>testing-modules/selenium-junit-testng</module>
<module>persistence-modules/solr</module> <module>persistence-modules/solr</module>
<module>spark-java</module> <module>spark-java</module>
<!-- <module>spring-5</module>--> <!-- <module>spring-5</module>-->
@ -235,8 +235,8 @@
<module>spring-rest-embedded-tomcat</module> <module>spring-rest-embedded-tomcat</module>
<module>testing</module> <module>testing-modules/testing</module>
<module>testng</module> <module>testing-modules/testng</module>
<module>video-tutorials</module> <module>video-tutorials</module>
@ -254,7 +254,7 @@
<module>drools</module> <module>drools</module>
<module>persistence-modules/liquibase</module> <module>persistence-modules/liquibase</module>
<module>spring-boot-property-exp</module> <module>spring-boot-property-exp</module>
<module>mockserver</module> <module>testing-modules/mockserver</module>
<module>undertow</module> <module>undertow</module>
<module>vertx-and-rxjava</module> <module>vertx-and-rxjava</module>
<module>saas</module> <module>saas</module>

View File

@ -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;
}
}

View File

@ -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;

View File

@ -0,0 +1,5 @@
CREATE TABLE country (
id INTEGER NOT NULL AUTO_INCREMENT,
name VARCHAR(128) NOT NULL,
PRIMARY KEY (id)
);

View File

@ -0,0 +1 @@
spring.jpa.hibernate.ddl-auto=none

View File

@ -122,6 +122,25 @@
<artifactId>jstl-api</artifactId> <artifactId>jstl-api</artifactId>
<version>${jstl.version}</version> <version>${jstl.version}</version>
</dependency> </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> </dependencies>

View File

@ -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());
}
}

View File

@ -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;
}
}

View File

@ -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 {
}

View File

@ -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);
}

View File

@ -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;
}
}

View File

@ -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)
;

View File

@ -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);

View File

@ -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

View File

@ -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);
}
}

View File

@ -17,6 +17,7 @@
<groupId>com.baeldung</groupId> <groupId>com.baeldung</groupId>
<artifactId>parent-modules</artifactId> <artifactId>parent-modules</artifactId>
<version>1.0.0-SNAPSHOT</version> <version>1.0.0-SNAPSHOT</version>
<relativePath>../</relativePath>
</parent> </parent>
<build> <build>

View File

@ -4,16 +4,17 @@
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>
<!-- NOT NEEDED - JSP <groupId>com.baeldung</groupId>--> <!-- NOT NEEDED - JSP <groupId>com.baeldung</groupId>-->
<artifactId>junit5</artifactId> <artifactId>junit-5</artifactId>
<version>1.0-SNAPSHOT</version> <version>1.0-SNAPSHOT</version>
<name>junit5</name> <name>junit-5</name>
<description>Intro to JUnit 5</description> <description>Intro to JUnit 5</description>
<parent> <parent>
<groupId>com.baeldung</groupId> <groupId>com.baeldung</groupId>
<artifactId>parent-modules</artifactId> <artifactId>parent-modules</artifactId>
<version>1.0.0-SNAPSHOT</version> <version>1.0.0-SNAPSHOT</version>
<relativePath>../</relativePath>
</parent> </parent>
<properties> <properties>

Some files were not shown because too many files have changed in this diff Show More