Difference between revisions of "How to Customize and Extend opentaps 2 with your own OSGi Bundle"
Line 39: | Line 39: | ||
</pre> | </pre> | ||
− | + | But how do we get the security implementation into the service? This is done in an Inversion Of Control (IOC) pattern. First, we provide for the security with a hook in CreateNoteServiceImpl: | |
− | + | <pre> | |
− | + | private volatile NoteSecurity security = null; | |
+ | |||
+ | public void setNoteSecurity(NoteSecurity noteSecurity) { | ||
+ | if (security == null && noteSecurity != null) { | ||
+ | synchronized (this) { | ||
+ | if (security == null) { | ||
+ | security = noteSecurity; | ||
+ | } | ||
+ | } | ||
+ | } | ||
+ | } | ||
+ | </pre> | ||
+ | |||
+ | Now, we won't put anything in the code for where the security there. This is good, because when we change the security implementation later, we don't have to change the create note service. Instead, we'll use OSGI blueprint to wire the two together. I'll put some directives to modules/notes/impl/services/src/main/resources/OSGI-INF/blueprint/blueprint.xml: | ||
+ | |||
+ | <pre> | ||
+ | <reference id="noteSecurityService" interface="org.opentaps.notes.security.NoteSecurity"/> | ||
+ | |||
+ | <bean id="createNoteServiceImpl" class="org.opentaps.notes.services.impl.CreateNoteServiceImpl"> | ||
+ | <property name="noteSecurity" ref="noteSecurityService"/> | ||
+ | </bean> | ||
+ | </pre> | ||
+ | |||
+ | What we're saying is that there is something called noteSecurityService, it is org.opentaps.notes.security.NoteSecurity, and we will use the CreateNoteServiceImpl.setNoteSecurity method to set it. This is equivalent to: | ||
+ | <pre> | ||
+ | CreateNoteServiceImpl obj = new CreateNoteServiceImpl(); | ||
+ | obj.setNoteRepository(InitialContext.lookup("org.opentaps.notes.repository.NoteRepository")); | ||
+ | </pre> | ||
+ | where org.opentaps.notes.repository.NoteRepository in value of property osgi.jndi.service.name of the service. | ||
+ | |||
+ | In my security implementation module, I will also have a blueprint XML file, in modules/notes/impl/security/src/main/resources/OSGI-INF/blueprint/blueprint.xml. Here is where I define: | ||
+ | <pre> | ||
+ | <bean id="noteSecurityImpl" class="org.opentaps.notes.security.impl.NoteSecurityImpl"> | ||
+ | </bean> | ||
+ | |||
+ | <service id="noteSecurityService" ref="noteSecurityImpl" interface="org.opentaps.notes.security.NoteSecurity"> | ||
+ | <service-properties> | ||
+ | <entry key="osgi.jndi.service.name" value="org.opentaps.notes.security.NoteSecurity"/> | ||
+ | </service-properties> | ||
+ | </service> | ||
+ | </pre> | ||
+ | |||
+ | Which says "I am implementing org.opentaps.notes.security.NoteSecurity with org.opentaps.notes.security.impl.NoteSecurityImpl." Note you have to define the entry key for osgi.jndi.service.name, or this name can be used to find service with service registry but not with JNDI lookup. Also, it is important to note that it is the full interface class name (org.opentaps.notes.security.NoteSecurity) which is used to link the implementation to the interface, not the service or bean id attribute. |
Revision as of 00:39, 8 March 2012
Ok, you've been patient and reading through all the other tutorials. But at some point, you've probably wondered -- what's the big idea here?
This tutorial will show you.
The most important thing for successful enterprise software is modularity: Separate and maintainable modules for each part of the application. OSGi lets you extend and customize your application with your own bundle. Even better, it lets you manage those bundles in real time, so you can manage your application by loading and unloading bundles from the Geronimo console.
In this tutorial, we will add security permissions to our opentaps 2 Notes application and then show you how to implement an OSGi bundle which overrides the base permission with your own. You can then see how you can deploy and undeploy the bundle in real time to change the security permissions of your system without restarting the server.
The first step is to create a new package, org.opentaps.notes.security, and a new interface NoteSecurity. All it does is define some operations and a security method:
public interface NoteSecurity { public static enum Operation {CREATE, UPDATE, DELETE}; public boolean hasPermission(Note note, Operation permissionId); public String getErrorMessage(); }
Then, I implement my security feature with a new module in notes/impl/security. I follow the steps from [[]] to create a new module. The code itself is trivial:
public class NoteSecurityImpl implements NoteSecurity { @Override public boolean hasPermission(Note note, String permissionId) { Log.logInfo("This test implementation will always return true, so I will let you create your note."); return true; } }
Next, I modify my CreateNoteServiceImpl to check security before creating the Note:
if (!security.hasPermission(note, NoteSecurity.Operation.CREATE)) { throw new ServiceException(security.getErrorMessage()); }
But how do we get the security implementation into the service? This is done in an Inversion Of Control (IOC) pattern. First, we provide for the security with a hook in CreateNoteServiceImpl:
private volatile NoteSecurity security = null; public void setNoteSecurity(NoteSecurity noteSecurity) { if (security == null && noteSecurity != null) { synchronized (this) { if (security == null) { security = noteSecurity; } } } }
Now, we won't put anything in the code for where the security there. This is good, because when we change the security implementation later, we don't have to change the create note service. Instead, we'll use OSGI blueprint to wire the two together. I'll put some directives to modules/notes/impl/services/src/main/resources/OSGI-INF/blueprint/blueprint.xml:
<reference id="noteSecurityService" interface="org.opentaps.notes.security.NoteSecurity"/> <bean id="createNoteServiceImpl" class="org.opentaps.notes.services.impl.CreateNoteServiceImpl"> <property name="noteSecurity" ref="noteSecurityService"/> </bean>
What we're saying is that there is something called noteSecurityService, it is org.opentaps.notes.security.NoteSecurity, and we will use the CreateNoteServiceImpl.setNoteSecurity method to set it. This is equivalent to:
CreateNoteServiceImpl obj = new CreateNoteServiceImpl(); obj.setNoteRepository(InitialContext.lookup("org.opentaps.notes.repository.NoteRepository"));
where org.opentaps.notes.repository.NoteRepository in value of property osgi.jndi.service.name of the service.
In my security implementation module, I will also have a blueprint XML file, in modules/notes/impl/security/src/main/resources/OSGI-INF/blueprint/blueprint.xml. Here is where I define:
<bean id="noteSecurityImpl" class="org.opentaps.notes.security.impl.NoteSecurityImpl"> </bean> <service id="noteSecurityService" ref="noteSecurityImpl" interface="org.opentaps.notes.security.NoteSecurity"> <service-properties> <entry key="osgi.jndi.service.name" value="org.opentaps.notes.security.NoteSecurity"/> </service-properties> </service>
Which says "I am implementing org.opentaps.notes.security.NoteSecurity with org.opentaps.notes.security.impl.NoteSecurityImpl." Note you have to define the entry key for osgi.jndi.service.name, or this name can be used to find service with service registry but not with JNDI lookup. Also, it is important to note that it is the full interface class name (org.opentaps.notes.security.NoteSecurity) which is used to link the implementation to the interface, not the service or bean id attribute.