|
Welcome to the Enterprise Java Technologies Tech Tips for September 2007. Here you'll get tips on using enterprise Java technologies and APIs, such as those in Java Platform, Enterprise Edition (Java EE). You can now read the Enterprise Java Technologies Tech Tips online as a web log. This issue covers:
These tips were developed using an open source reference implementation of Java EE 5 called GlassFish, and the open source NetBeans IDE 5.5.1. You can download GlassFish from the GlassFish Community Downloads page. You can download the NetBeans IDE 5.5.1 from the NetBeans page. You can download the sample archive for the tip Using Type Substitution With Web Services. You can download the sample archive for the tip Improving JSF Security Configuration With Secured Managed Beans. Any use of this code and/or information below is subject to the license terms. Using Type Substitution with Web Services
By Doug Kohlert
Java Architecture for XML Binding (JAXB) 2.1 introduced a new annotation, This tip will show you how to develop a simple web service that uses type substitution as well a client that consumes the web service. You'll see how to build the web service from a Java class and from a WSDL file. A sample application accompanies this tip. The code examples in the tip are taken from the source code of the sample application. Using Type Substitution in a Web Service Suppose you want to build a web service that manages the inventory for a store that sells wakeboards and related equipment. Wakeboards are short boards made of buoyant material that are used to ride over the surface of a body of water, typically behind a boat or with a cable-skiing apparatus.
For simplicity, let's assume that the store sells only three types items: wakeboards, bindings, and towers for boats. You
want the web service to be fairly simple to use and have a minimal amount of exposed operations. So to keep things
simple, the web service uses an abstract public abstract class Item implements Serializable { private long id; private String brand; private String name; private double price; ... }
Extending the public class Wakeboard extends Item { private String size; } public class WakeboardBinding extends Item { private String size; } public class Tower extends Item { private Fit fit; private String tubing; public static enum Fit { Custom, Exact, Universal }; }
Because this example is about type substitution, let's make the inheritance hierarchy a little more interesting by introducing
a public abstract class Wearable extends Item { protected String size; }
And the resulting public class Wakeboard extends Wearable { } public class WakeboardBinding extends Wearable { }
Also, because the web service manages inventory, you'll want the inventory items to be persisted to a database using the Java Persistence API (sometimes referred to as JPA). To do this, you need to add an The final data classes look like the following: @Entity @Inheritance(strategy=InheritanceType.JOINED) public abstract class Item implements Serializable { @Id @GeneratedValue(strategy = GenerationType.AUTO) private Long id; private String brand; private String itemName; private double price; // Getters & setters ... } @MappedSuperclass public abstract class Wearable extends Item { protected String size; ... } @Entity public class Wakeboard extends Wearable {} @Entity public class WakeboardBinding extends Wearable {} @Entity public class Tower extends Item { private Fit fit; private String tubing; public static enum Fit { Custom, Exact, Universal }; ... }
Now that you defined the data model for the application, you can now define the web service interface. Because the application manages information about wakeboard equipment, let's call the web service
Here is what the @WebService() public class WakeRider { ... public List<Item> getItems() {...} public boolean addItem(Item item) {...} public boolean updateItem(Item item) {...} public boolean removeItem(Item item) {...} }
If you deployed this web service and then looked at the generated WSDL and schema, you would notice that only the
Here is what the @WebService() @XmlSeeAlso({Wakeboard.class, WakeboardBinding.class, Tower.class}) public class WakeRider { ... }
Now when you deploy the Starting From WSDL
You can use type substitution in a web service that is built from a WSDL file. What's particularly nice about this is that
using type substitution when starting from WSDL is totally transparent. When you import a WSDL file with JAX-WS 2.1, the
generated proxy class is required to have the appropriate @WebService(name="WakeRider", targetNamespace="http://wakerider/") @XmlSeeAlso({ObjectFactory.class}) public interface WakeRider { ... }
Notice that the The WakeRider Client
Invoking the
There is also a NetBeans 5.5.1 project for a JavaServer Faces (JSF) technology application named
Both of these client applications contain code similar to the following for invoking an operation on the WakeRiderService service = new WakeRiderService(); port = service.getWakeRiderPort(); List<Item> items = port.getItems(); for (Item item : items) { if (item instanceof Wakeboard) { ... } else if (Item instance of WakeboardBinding) { ... } else if (Item instance of Tower) { ... } }Running the Sample Code The sample code for this tip is available as three NetBeans projects:
You can build and run the sample code using the NetBeans 5.5.1 IDE as follows:
About the Author Doug Kohlert is a senior staff engineer in the Web Technologies and Standards division of Sun Microsystems where he is the specification lead for JAX-WS. Improving JSF Security Configuration with Secured Managed Beans
Java EE allows you to protect web resources through declarative security, but this approach does not allow you to protect local beans used by servlets and JavaServer Pages (JSPs). Also, although you can protect JavaServer Faces technology (JSF) pages using declarative security, this is often not sufficient. This tip will show you a way to extend JSF security configuration beyond web pages using managed bean methods. Introduction
Java EE allows you to protect web pages and other web resources such as files, directories, and servlets through declarative
security. In this approach you declare in a <security-constraint> <display-name>Sample</display-name> <web-resource-collection> <web-resource-name>members</web-resource-name> <description/> <url-pattern>/members.jsf</url-pattern> <http-method>GET</http-method> <http-method>POST</http-method> </web-resource-collection> <auth-constraint> <description/> <role-name>admin</role-name> </auth-constraint> </security-constraint> <security-role> <description/> <role-name>admin</role-name> </security-role>
Notice that you identify the resources you want to protect by specifying their URLs in a Also, although you can protect JSF pages using declarative security, this is often not sufficient. For example, you might want a JSF application to present the same page to users with different roles, but only allow some of those roles to perform specific operations. For instance, you might allow users with all of those roles to read and update data, but allow users with specific roles to create and delete data. In that case, you need a way to extend JSF security beyond web pages. Additionally, declarative security doesn't check roles during the request processing commonly used by MVC frameworks and JSF. As a result, a managed bean can return any view id even if it's for a protected resource. This can potentially expose protected resources to a role that should not have access to them. One solution is to use JBoss Seam Web Beans or JSR 299: Web Beans. Web Beans allow you to configure page security, component security, and even Java Persistence Architecture entity security. However, many companies are adopting simpler security solutions without Seam, Spring, EJB, or security-specific frameworks. The technique covered in this tip demonstrates a simple approach that extends JSF security using annotations in managed beans methods. A sample application accompanies this tip. The code examples in the tip are taken from the source code of the sample application. Declare the Extended JSF ActionListener and NavigationHandler
To provide managed bean method protection you need to declare the extended JSF
To enable the classes, you declare the following elements inside the <!-- JSF-security method--> <application> <action-listener> br.com.globalcode.jsf.security.SecureActionListener </action-listener> <navigation-handler> br.com.globalcode.jsf.security.SecureNavigationHandler </navigation-handler> </application>
For example, the following code renders a JSF page with a View button and a Delete button. <h:form id="sampleSecurity"> <h:commandButton value="View" id="unprotectedButton" action="#{CustomerCRUD.view}"/> <h:commandButton value="Delete" id="protectedButtonprotectedButton" action="#{CustomerCRUD.delete}"/> </h:form>
When the user clicks on the Delete button, a call is made to the public class CustomerCRUD { public String view() { return "view-customer"; } @SecurityRoles("customer-admin-adv, root") public String delete() { System.out.println("I'm a protected method!"); return "delete-customer"; } ...
Set Up User Object Providers
By adding a context parameter into
Set Up the ContainerUserProvider The web container provider approach is integrated with declarative security, so it can be used with applications that already use declarative security. Add the following context parameter to set up the default container user provider: <context-param> <param-name>jsf-security-user-provider</param-name> <param-value> br.com.globalcode.jsf.security.usersession.ContainerUserProvider </param-value> </context-param>Here is what the default web container user provider class looks like: public class ContainerUserProvider implements UserProvider { ContainerUser user = new ContainerUser(); public User getUser() { if(user.getLoginName()==null || user.getLoginName().equals("")) { return null; } else { return user; } }
public class ContainerUser implements User { public String getLoginName() { if(FacesContext.getCurrentInstance().getExternalContext(). getUserPrincipal()==null) return null; else return FacesContext.getCurrentInstance(). getExternalContext().getUserPrincipal().toString(); } public boolean isUserInRole(String roleName) { return FacesContext.getCurrentInstance().getExternalContext(). isUserInRole(roleName); }Using a SessionUserProvider If your solution uses a custom security authentication and authorization process, you can provide a user class adapter that implements the given user interface and bind a user object instance into the HTTP Session with the key name "user". This approach works well for legacy Java EE or J2EE applications that don't use declarative security.
Follow these steps to set up your application to use a
Running the Sample Code A sample package accompanies this tip. This sample runs with aSessionUserProvider and has a very simple user and login page.
To install and run the sample:
Click on both buttons and see what happens. You'll see that you can run the unprotected method, but the protected method requires you to have a special role.
About the Author Vinicius Senger is a performance researcher, Java EE architect, and instructor. He started his career at Sun Microsystems and Oracle as independent consultant and official instructor, and later founded Globalcode, a leading Java-related training company in Brazil. Vinicius is a member of the JSF 2.0 Expert Group, the leader of the Global Education and Learning Community, a NetBeans Dream Team Member, and project leader of JAREF, an educational and research framework. He is also a Sun Certified Enterprise Architect and Programmer P1. | ||||||||||
|
| ||||||||||||