Showing posts with label ADF. Show all posts
Showing posts with label ADF. Show all posts

Saturday, August 17, 2019

A Few More Thoughts about Infra

I know, I know, it has been months since I posted.  Personal note: My life got a bit complicated in late February and early March, and then at the end of April, I started a new job.  My work on Infra moved from being my main professional project to being a labor of love that I fit in whenever I can spare some energy from the projects that pay the bills.  So, I'm going to write a few more thoughts on Infra here, and then I'll write a few posts on some items that came out of my current paid gig.

Application Implementation Considerations and Options

With the database design done, engineered to a relational design and some physical implementation scripts generated, my attention turned to the front end implementation of INFRA.

Requirements

INFRA is intended to be available as an application that anyone can install on just about any relational database and just about any application infrastructure. And I don’t want cost to be a major factor for anyone who wants to use it, so I want to look at free to use frameworks and tools. I say “free to use” because I have expertise in Oracle tools and frameworks, and while these are not open source, there are several options that are free to use. Still, many potential users of INFRA will prefer not to be locked into the tools of a single vendor (and I’m afraid they are strongly biased AGAINST Oracle), and thus will prefer open source.
As for requirements, I’d prefer to stick with standards and especially do as much with plain HTML and CSS as possible. I also want good tooling, and am very fond of having the tools do as much of the work as possible. So I want a good IDE with good support for the chosen framework. I have nothing against a good text editor to write short programs where I am hand writing most of the code. For an entire project, however, nothing beats a good IDE, and I have experience with three, NetBeans, Eclipse and Oracle JDeveloper. So here is a little about the choices I considered:

Oracle Application Development Framework (ADF)

ADF has been my professional choice since 2010, and I am still the Lead Moderator for the ADF Enterprise Methodology Group (ADF EMG). So despite the bias against anything from Oracle, I needed to consider ADF, because I can hit the ground running with it. ADF is certainly not open source, which is a mark against it, but there is a subset of ADF called ADF Essentials that is free to use. Unfortunately, the full ADF product only runs on Oracle WebLogic Server (WLS), but ADF Essentials is supported on Glassfish, and is known to work on several other JEE standards compliant application servers, like JBoss and with careful configuration on Apache Tomcat. ADF is a Model/View/Controller (MVC) based framework. It supports the JPA standard for Object Relational Mapping (ORM) for its Model and Java Server Faces (JSF) for its View. The ADF Faces JSF component library has lots of widgets that give you lots of options for layout, data presentation, and input/update forms.
My favorite part of ADF is tooling. You can develop ADF Essentials applications in Oracle JDeveloper, but you do have to be careful to stay away from parts of ADF that require the full tool – i.e. must be deployed on WLS. But JDeveloper has wonderful WYSIWYG support for ADF Faces (and Apache Trinidad) components and can do things like let you drag fields from your ORM onto a page and generate a table component configured to display them, or a form to insert, update or delete data in the database. There have been complaints that JDeveloper is slow and buggy however, and it isn’t in very wide use outside the Oracle user community. As an alternative, you can develop ADF Essentials applications with Eclipse by installing the Oracle Enterprise Pack for Eclipse (OEPE). OEPE doesn’t show ADF Faces components quite as well as JDeveloper, and doesn’t have as much code generation, but it is not bad, and probably a little more stable.
The problems with ADF are: It isn’t open source. Oracle’s support for ADF has been waning, and that means that updates of ADF and of JDeveloper have been very widely spaced. Later versions of JDeveloper have bugs that have not been adequately addressed. It has never gained a large following in the developer community. But to me, the killer that sent me looking for an alternative is that ADF Essentials does not support ADF Security for authorization and authentication of your application. In earlier versions of ADF, this was okay because you COULD configure standard JEE security instead, or use a third party security framework like Spring Security or Apache Shiro. But the latest versions of ADF Essentials broke this, and while I’ve developed a work around, I’m not happy with it.

Other JSF Libraries

Java Server Faces is a JEE standard for the View and Controller, and so is JPA for the Model. Through ADF, I was already familiar with how these work, so a different set of JSF components seemed like a good option. There are a number of libraries around, many of which are open source.

Apache Trinidad

One faces library that appealed to me is Apache Trinidad, which originated as Oracle’s earlier 10g version of ADF Faces (current version is 12c 2.3), so I had actually used this in my first few ADF projects. Oracle opened the source to this library and contributed it to the Apache MyFaces project. This is under active development. One nice thing about Trinidad is that both JDeveloper and Eclipse with OEPE have tooling support for it, so you can get some of the drag and drop and code generation features of these tools without tying yourself to Oracle’s proprietary ADF Faces. Or you can add JSF and the Trinidad library to an Eclipse project without using OEPE.
Unfortunately, Trinidad is also not terribly popular among non-Oracle developers. It has been enhanced to keep up with the latest JSF standard, but not much for functionality.

PrimeFaces 

This is probably the most popular JSF library, with good documentation, good examples and sample code.  There is reasonable support for it in both NetBeans and in Eclipse (I have only used these and Oracle JDeveloper as my IDE.) but there isn't much WYSIWYG support.  Very cool is the ability, like ADF, to have themes, and even to let users switch themes.  And the themes are fairly standard - they are based on JQueryUI and tools for developing them are easily available.  You can even get a good number of themes from PrimeFaces' main developer, PrimeTek.  One interesting thing, is that there are projects for PrimeFaces-like UI that works with Angular - PrimeNG, and with React - PrimeReact.

Conclusion

So this is probably my last post on Infra for the time being. It remains an active project, but I still haven't chosen a UI from one of these or perhaps one of the JavaScript frameworks.  And development has slowed to a crawl.  Hard to come home from a hard day of development, and start up the computer for a private project.  But I've accumulated some nice tidbits on SQL Developer Data Modeler to share with my readers - coming to this blog real soon.

Thursday, May 18, 2017

Javascript Frameworks

Continuing on with a few opinions about UI design, development and implementation ...



So what is "cool" now?  Javascript frameworks like Angular, Ember, React and Oracle's own JET. These are great, and they have their place, I'm sure.  The argument is that since these frameworks use the power of the user's browser, they can be more responsive.  There is less communication between the server and the client, which should also speed things up. They can do exactly what the designer wants them to do - no component framework getting in the way, wanting to do things its way.  They are open source for the most part, which frees us from Oracle's tyranny.  And working in HTML and CSS can let you use graphic designers and their toolboxes, like DreamWeaver.

The first problem I have with Javascript frameworks is that this is a return to code it yourself.  The tooling builds some of the code as sample files, where you take some prebuilt code and tweak it.  For the most part, however, you have to write the HTML, the CSS, the Javascript.  Fortunately, there is some help in the libraries, like JQueryUI, with some precoded components, and lots of sample code.  But I miss JDeveloper's ability to drag a data control onto a page, say you want to drop it as a bar graph, do a little configuration, and presto.

Tooling and IDEs

Of course, in some respects, this is a problem with tooling rather than with the framework.  I suppose that if I could point Eclipse or Netbeans at a REST service and have it generate the code for say, an Angular 2 service module that accesses the service, I might feel differently.  Or if I could generate a first-cut form to do CRUD with that service, I'd feel better about these frameworks.  I also get the feeling that developers WANT to code it, and hate handing over part of the job to someone else, especially with something like ADF, where you can't easily see the source code.

The proponents say, "but you can make it look EXACTLY the way you want."  True, but at what cost? Can your users wait while you do it?  But you say "It's Agile, we'll do 80% now and get it closer to 100% with each iteration."  And I reply, "I can give you 98% in the time it takes you to do 80%, and do the users care if I can't get to 100%?"  If they DO care, guess what, ADF 12.2.1 uses JSF 2.2 (and so do the latest versions of other Faces libraries), and you CAN code in HTML5/CSS/Javascript what you can't do with JSF, yet still interact with the pure JSF parts. Someday, I'd love to do a contest - who can meet the user's requirements fastest.

Responsiveness and Speed

Another advantage claimed for these environments is that most of the processing takes place on the user's computer, and interacts directly with the browser.  Since the application doesn't have to interact with the server as much, it runs faster.  And on the server side, it isn't as complicated and doesn't require as much server resources.  All the server is doing is downloading files to the client, and running REST services.  What's more, the browser usually caches files that it has already downloaded, so if the file hasn't changed, it will use its local copy of the file, and won't go to the server for a fresh copy.  Please note that this can be a disadvantage for mobile devices with slow connections and limited storage.  There is a lot more code to be downloaded and stored.

The honest truth is that in ADF Faces many of the Rich Faces components are rendered using Oracle JET, so they have all the responsiveness of this Javascript library, except that I didn't have to code it.  Similarly, PrimeFaces renders with JQuery and JQueryUI.  Because PrimeFaces does this, it can use JQuery tools to create themes.  ADF Faces uses skinning through CSS-like files and the basis for its skins is in the open source Apache Trinidad Faces library.  Of course, this means that JSF frameworks can be subject to some of the same problems as the Javascript frameworks that they use for rendering.

Testing and Security

One problem that I have with Javascript frameworks is that all of the source code is delivered to the user's browser.  Javascript is interpreted code, which means that some bugs won't show themselves until runtime.  Compilers can catch some problems up front, which can speed development.  I should note that Angular 2 & 4 are usually written in Typescript which compiles to Javascript - a little of the best of both worlds.  But the biggest problem I have with this is the advantage it gives to hackers.  When a hacker can see ALL of the source code, including code that is intended to keep bad data out of the database, he/she can re-write it to bypass your safeguards.  If you are going to write REST services for your Javascript framework to use, you need to make sure that you have server-side protection.  Never accept data from a browser without validating it at the server.  Don't assume that the Javascript code that you wrote will be executed unchanged.

So there I am – an old developer who found a great way to develop and doesn't want to give it up.  I'm not against the Javascript frameworks, and if you want to build applications that way, good for you.  I'll do my best to support you.  I know enough HTML and CSS to be useful, and even some Javascript.  As a long-time database advocate, SQL and PL/SQL expert and developer, I'll write good solid secure REST services for you.  Does that make me obsolete?  I don't believe so.  I'm not quite ready to leave you without my help and advice yet.

Monday, May 15, 2017

User Interfaces - a Personal History

I've been doing user interfaces (UI) for a long time.  I hate to say how long, because I'm looking for a new job, and I'm afraid that age discrimination is very real.  And I'm also aware that behind my back some of my younger colleagues think that I'm set in my ways, behind the times, and in short, obsolete.

A little history

To be sure, my first user interfaces were a sort of template for users to enter data into a fixed record format file,  The only validations were to designate fields as alphanumeric or numeric.  My next applications let me draw forms on a terminal, and that gave me the ability to write (in COBOL of all things) code to validate and then write data to data files.  I graduated from there to Oracle Forms.  What a difference!  Now I could point my tool at a relational table, even several tables in master/detail relationships, and it would generate a first cut at forms to update those tables.
Oddly, my next step was a step back - I was working in HTML and once again had to develop my own forms and write my own code to process the input and decide which tables to update and what to feed back to my users.  At least PL/SQL is an easier language for that than COBOL.  In about 2000, it was nice to get a hold of Oracle Designer, and its web generation capability, which would create forms for me.  But then, I lost a lot of control over what the form looked like - unless I wanted to take COMPLETE control and not be able to regenerate the form from Designer,

Application Development Framework

Which brings me to Oracle Application Development Framework (ADF),  ADF Faces, the view and controller part of ADF is based on Java Server Faces (JSF), which is part of the Java Enterprise Edition (JEE) standard.  Oracle JDeveloper, the primary IDE for ADF, can generate first cuts at forms, but not just forms: ADF can do tables, graphs, hierarchies, trees, calendars and other data visualization.  It can drill down.  It can navigate from page to page, and this flow of control is shown graphically so that even showing it to a user, the user can get an idea how it is going to work.
A lot of the components have built-in functionality that I don't have to code.  For instance, an ADF table component can let users reorder columns, re-sort, and filter, with no code.  There are tabbed layouts, split screens (vertically or horizontally), and accordion layouts.  There are popups and quite a bit of control over when a popup is displayed and when hidden.  Some layout components are especially designed to rearrange themselves according to the size of the screen - showing differently on a phone than on a desktop for instance. The newest version of ADF can inform the application about the screen dimensions so that the application can decide what components to show.
ADF can do single page applications where the header, main menu and footer are all static with only the content in the middle changes.  It can do AJAX, changing only the parts of the page that need refreshing.

Other JEE/JSF Frameworks

One of the arguments against Oracle ADF is that it is Oracle.  And it is not open source – if you are on a support contract, you can get the source code, but you will need to sign a non-disclosure agreement and you can't change it.  Many people would prefer to use open source software only, and avoid depending on Oracle.

I can't argue with the advantages of going the open source route.  ADF Essentials lets me use ADF for free, and I can use an open source JEE application server.  And I've written an ADF application against an open source database, so we don't HAVE to use Oracle's expensive RDBMS.  But even ADF Essentials is NOT open source, and it doesn't do everything the non-free version can do on the non-free Oracle WebLogic Server.  We can get away from ADF BC and use an open source JPA implementation - and if you write ADF Essentials applications with Eclipse, you probably will do that. To get away from the ADF Controller and ADF Faces to an open source replacement, you can use the base JSF controller and an open source JSF library like PrimeFaces.  But in doing this, you will lose some of the wonderful tooling that JDeveloper has for code generation.  Or even Oracle Enterprise Pack for Eclipse has pretty good tools for developing ADF Essentials applications with EclipseLink for the Model and ADF Faces for the View and Controller.

I have also used some of the tools in Eclipse for developing PrimeFaces, and it is better than using the Javascript frameworks, but not as good as ADF Faces in JDeveloper.  In my next post, I'm going to talk about the Javascript frameworks.

Friday, March 3, 2017

A Work-Around for Security in ADF Essentials 12.2.1

In my previous post, I talked about ADF Essentials and configuring it for authentication and authorization.  And I reported a problem with the new 12.2.1 versions that raises an exception trying to initialize a UserProfile object.  I surmise that Oracle's newer versions call a facility that is only in Oracle WebLogic server, and NOT in the typical application server running ADF Essentials, notably Glassfish.  But, until Oracle fixes this (PLEASE Oracle) I have tested a workaround.  This was suggested by a comment on this post by Andrejus Baranovski (and if you are using ADF, you NEED to read Andrejus' blog - it is GREAT!)  http://andrejusb.blogspot.com/2012/10/adf-essentials-security-implementation.html.

The comment is by Ivan Melluso, who said:
I'm using JDeveloper 12.2.1, Glassfish 4.1.1, ADF Essentials 12.2.1;
I obtained
NoClassDefFoundError: Could not initialize class oracle.adf.share.security.identitymanagement.UserProfile
Then I discover the UserProfile class initialize a MDS session, that can't exists in GlassFish;

My solution:
- Decompile the class
- Rewrite it preserving package name and all public methods
- Create a new jar
- Place it in /lib directory

I restart the server 5 times to check the class conflict (same class exists in adf-share-ca.jar and my jar) and all 5 times I don't obtain the error
So the work-around is to write our own version of UserProfile and get the application to call ours instead of Oracle's original.  Here is my version:

package oracle.adf.share.security.identitymanagement;

import java.io.Serializable;

import java.security.Principal;

import java.util.HashMap;

import javax.faces.context.FacesContext;

public class UserProfile implements Serializable {
    @SuppressWarnings("compatibility:-6264967054558894560")
    private static final long serialVersionUID = 1L;

    public UserProfile() {
        super();
    }

    java.util.HashMap properties = new HashMap();


    public Object getProperty(String propName) {
        return properties.get(propName);
    }

    public void setProperty(String name, Object value) {
        properties.put(name, value);
    }

    public void setBusinessCity(String businessCity) {
        setProperty("businessCity", businessCity);
    }

    public String getBusinessCity() {
        return (String)getProperty("businessCity");
    }

    public void setBusinessCountry(String businessCountry) {
        setProperty("businessCountry", businessCountry);
    }

    public String getBusinessCountry() {
        return (String)getProperty("businessCountry");
    }

    public void setBusinessEmail(String businessEmail) {
        setProperty("businessEmail", businessEmail);
    }

    public String getBusinessEmail() {
        return (String)getProperty("businessEmail");
    }

    public void setBusinessFax(String businessFax) {
        setProperty("businessFax", businessFax);
    }

    public String getBusinessFax() {
        return (String)getProperty("businessFax");
    }

    public void setBusinessMobile(String businessMobile) {
        setProperty("businessMobile", businessMobile);
    }

    public String getBusinessMobile() {
        return (String)getProperty("businessMobile");
    }

    public void setBusinessPager(String businessPager) {
        setProperty("businessPager", businessPager);
    }

    public String getBusinessPager() {
        return (String)getProperty("businessPager");
    }

    public void setBusinessPhone(String businessPhone) {
        setProperty("businessPhone", businessPhone);
    }

    public String getBusinessPhone() {
        return (String)getProperty("businessPhone");
    }

    public void setBusinessPOBox(String businessPOBox) {
        setProperty("businessPOBox", businessPOBox);
    }

    public String getBusinessPOBox() {
        return (String)getProperty("businessPOBox");
    }

    public void setBusinessPostalAddr(String businessPostalAddr) {
        setProperty("businessPostalAddr", businessPostalAddr);
    }

    public String getBusinessPostalAddr() {
        return (String)getProperty("businessPostalAddr");
    }

    public void setBusinessPostalCode(String businessPostalCode) {
        setProperty("businessPostalCode", businessPostalCode);
    }

    public String getBusinessPostalCode() {
        return (String)getProperty("businessPostalCode");
    }

    public void setBusinessState(String businessState) {
        setProperty("businessState", businessState);
    }

    public String getBusinessState() {
        return (String)getProperty("businessState");
    }

    public void setBusinessStreet(String businessStreet) {
        setProperty("businessStreet", businessStreet);
    }

    public String getBusinessStreet() {
        return (String)getProperty("businessStreet");
    }

    public void setDateofBirth(String dateofBirth) {
        setProperty("dateofBirth", dateofBirth);
    }

    public String getDateofBirth() {
        return (String)getProperty("dateofBirth");
    }

    public void setDateofHire(String dateofHire) {
        setProperty("dateofHire", dateofHire);
    }

    public String getDateofHire() {
        return (String)getProperty("dateofHire");
    }

    public void setDefaultGroup(String defaultGroup) {
        setProperty("defaultGroup", defaultGroup);
    }

    public String getDefaultGroup() {
        return (String)getProperty("defaultGroup");
    }

    public void setDepartment(String department) {
        setProperty("department", department);
    }

    public String getDepartment() {
        return (String)getProperty("department");
    }

    public void setDepartmentNumber(String departmentNumber) {
        setProperty("departmentNumber", departmentNumber);
    }

    public String getDepartmentNumber() {
        return (String)getProperty("departmentNumber");
    }

    public void setDescription(String description) {
        setProperty("description", description);
    }

    public String getDescription() {
        return (String)getProperty("description");
    }

    public void setDisplayName(String displayName) {
        setProperty("displayName", displayName);
    }

    public String getDisplayName() {
        return (String)getProperty("displayName");
    }

    public void setEmployeeNumber(String employeeNumber) {
        setProperty("employeeNumber", employeeNumber);
    }

    public String getEmployeeNumber() {
        return (String)getProperty("employeeNumber");
    }

    public void setEmployeeType(String employeeType) {
        setProperty("employeeType", employeeType);
    }

    public String getEmployeeType() {
        return (String)getProperty("employeeType");
    }

    public void setFirstName(String firstName) {
        setProperty("firstName", firstName);
    }

    public String getFirstName() {
        return (String)getProperty("firstName");
    }

    public void setGivenName(String givenName) {
        setProperty("givenName", givenName);
    }

    public String getGivenName() {
        return (String)getProperty("givenName");
    }

    public void setGUID(String GUID) {
        setProperty("GUID", GUID);
    }

    public String getGUID() {
        return (String)getProperty("GUID");
    }

    public void setHomeAddress(String homeAddress) {
        setProperty("homeAddress", homeAddress);
    }

    public String getHomeAddress() {
        return (String)getProperty("homeAddress");
    }

    public void setHomePhone(String homePhone) {
        setProperty("homePhone", homePhone);
    }

    public String getHomePhone() {
        return (String)getProperty("homePhone");
    }

    public void setInitials(String initials) {
        setProperty("initials", initials);
    }

    public String getInitials() {
        return (String)getProperty("initials");
    }

    public void setJpegPhoto(byte[] jpegPhoto) {
        setProperty("jpegPhoto", jpegPhoto);
    }

    public byte[] getJpegPhoto() {
        return (byte[])getProperty("jpegPhoto");
    }

    public void setLastName(String lastName) {
        setProperty("lastName", lastName);
    }

    public String getLastName() {
        return (String)getProperty("lastName");
    }

    public void setMaidenName(String maidenName) {
        setProperty("maidenName", maidenName);
    }

    public String getMaidenName() {
        return (String)getProperty("maidenName");
    }

    public void setManager(String manager) {
        setProperty("manager", manager);
    }

    public String getManager() {
        return (String)getProperty("manager");
    }

    public void setMiddleName(String middleName) {
        setProperty("middleName", middleName);
    }

    public String getMiddleName() {
        return (String)getProperty("middleName");
    }

    public void setName(String name) {
        setProperty("name", name);
    }

    public String getName() {
        return (String)getProperty("name");
    }

    public void setNameSuffix(String nameSuffix) {
        setProperty("nameSuffix", nameSuffix);
    }

    public String getNameSuffix() {
        return (String)getProperty("nameSuffix");
    }

    public void setOrganization(String organization) {
        setProperty("organization", organization);
    }

    public String getOrganization() {
        return (String)getProperty("organization");
    }

    public void setOrganizationalUnit(String organizationalUnit) {
        setProperty("organizationalUnit", organizationalUnit);
    }

    public String getOrganizationalUnit() {
        return (String)getProperty("organizationalUnit");
    }

    public void setPreferredLanguage(String preferredLanguage) {
        setProperty("preferredLanguage", preferredLanguage);
    }

    public String getPreferredLanguage() {
        return (String)getProperty("preferredLanguage");
    }

    public Principal getPrincipal() {
        Principal principal =
            FacesContext.getCurrentInstance().getExternalContext().getUserPrincipal();
        return principal;
    }

    public void setProperties(HashMap properties) {
        setProperty("properties", properties);
    }

    public HashMap getProperties() {
        return (HashMap)getProperty("properties");
    }

    public void setTimeZone(String timeZone) {
        setProperty("timeZone", timeZone);
    }

    public String getTimeZone() {
        return (String)getProperty("timeZone");
    }

    public void setTitle(String title) {
        setProperty("title", title);
    }

    public String getTitle() {
        return (String)getProperty("title");
    }

    public void setUIAccessMode(String UIAccessMode) {
        setProperty("UIAccessMode", UIAccessMode);
    }

    public String getUIAccessMode() {
        return (String)getProperty("UIAccessMode");
    }

    public void setUniqueName(String uniqueName) {
        setProperty("uniqueName", uniqueName);
    }

    public String getUniqueName() {
        return (String)getProperty("uniqueName");
    }

    public void setUserID(String userID) {
        setProperty("userID", userID);
    }

    public String getUserID() {
        return (String)getProperty("userID");
    }

    public void setUserName(String userName) {
        setProperty("userName", userName);
    }

    public String getUserName() {
        return (String)getProperty("userName");
    }

    public void setWirelessAcctNumber(String wirelessAcctNumber) {
        setProperty("wirelessAcctNumber", wirelessAcctNumber);
    }

    public String getWirelessAcctNumber() {
        return (String)getProperty("wirelessAcctNumber");
    }
   
    public void saveProfile () {
        // do nothing
    }

}

Now, how to package it, and where to put it.  We need to make sure that ours is used instead of Oracle's.  We could do what Ivan did, and package it in our own jar and add the jar to the lib folder.  Well, I'm not confident that it will always use mine instead of Oracle's - depends on what the class loader does, and I'm not really that experienced with how java and Glassfish really work.  So I got out my trusty 7-Zip and replaced UserProfile in Oracle's jar, adf-share-ca.jar with my version of the class.  This works, no more Exception.

The real question - is this legal? If I started using this in production, could Oracle come after me.  Honestly, I doubt that they would bother, but could they?  On the other hand, if Oracle would fix this, I wouldn't do it.  After all, to deploy my application, I have to deploy MY version of adf-share-ca.jar, and I have to make a new version of the jar anytime Oracle's changes.

Wednesday, March 1, 2017

Authentication and Authorization in ADF Essentials 12.2.1.x on Glassfish 4

I think I’ve said before how much I appreciate that Oracle provides a subset of ADF functionality for free, in the library called ADF Essentials.  ADF Essentials will let you write ADF applications that can be deployed to pretty much any JEE standard application server, and Glassfish is specifically supported.  I find that this is a good selling point for ADF because my clients may find Oracle WebLogic Server (WLS) a bit hefty for their needs, and may balk at the licensing and support costs for WLS.

One of the problems with the early versions of ADF Essentials is that they are intended for Glassfish 3.1.2 and may not work properly with the latest version, Glassfish 4.1.1.  So I was delighted when ADF 12.2.1.0 was released, and included ADF Essentials from the beginning.  And it was certified for Glassfish 4.  I set to work, and soon I had my standard test application on the HR sample schema working in Glassfish 4.1.1 with ADF Essentials 12.2.1.1.  It ran just as well on Glassfish as it did on the Integrated WLS, maybe even as little faster.  Glassfish 4.1.1 has a few bugs and quirks that I wish would be fixed, and I’m sorry to say that Oracle is phasing out its support for the Open Source Glassfish project – so members of the community are going to have to step forth to continue the work.  But generally, it works.

Now for the next stage of my test application which was adding authentication and authorization.  One of the missing pieces in the ADF Essentials subset that is part of full ADF is ADF Security.  This is missing, because it relies on some capabilities that are part of WLS, and not part of the JEE standard.  This doesn’t mean that you can’t write secure applications with ADF Essentials, but you must use the capabilities that are part of the JEE standard or a third party library like Spring Security.  I’d done this before with ADF 12.1.3 and Glassfish 3.2.1, so I had some experience with setting it up.  The steps are:
  1. Add a security realm to Glassfish.  ADF defaults to using the name, “myrealm”, but you can change this and use pretty much any name you like.  For simple testing, you might want to use the “file” ream, which will allow you to add test users and their security groups in the Glassfish admin console.  Later, you can replace this with a realm based on an LDAP directory or some database tables.
  2. Optionally, add one or more security roles in web.xml.  These roles are used for authorization to govern what users may do in your application.  If you don’t use roles, you’ll have to authorize by username, so I always do this.
  3. Add one or more security constraints in web.xml.  In the simplest configuration, a constraint will protect particular pages in the application, and allow only certain users or users with certain roles to access these pages.  It can be more complex than that, but let’s stick with the simple case.  The application will require authentication only when the user tries to access a protected page, and has not yet been authenticated.
  4. Configure authentication in web.xml with the login-config element.  This tells the application server how to get the username and password.  There are several ways to do this, and the most common way is with a login form, so you may have to add a page with the required login fields.
  5. Add a glassfish-web.xml file in WEB-INF if you don’t already have one, and use it to map the security roles in web.xml to the security groups that will be returned from your Glassfish security realm.  You may need this file anyway to map the data sources used by your application to the data sources that you added to Glassfish.
So, I did these with my test application, re-deployed it, and tried it.  It showed the login page as expected, showed the error page if I typed in an incorrect username and/or password, but when I typed in the correct username and password, I saw the following error:
javax.servlet.ServletException: Filter execution threw an exception
root cause
java.lang.NoClassDefFoundError: Could not initialize class
 oracle.adf.share.security.identitymanagement.UserProfile 

After making sure that I had made no discernible error, I posted a question in the JDeveloper and ADF Forum on the Oracle Communities - Filter exception ADF Essentials 12.2.1.1 on Glassfish 4.  There was a considerable amount of discussion, and other people reported the same problem.  Several of us did some additional testing.  One thing I immediately learned is that the application works fine in the Integrated WebLogic Server.  This points to a problem that is related to running with ADF Essentials on Glassfish.

As far as I can determine, there has been a change to the ADF Controller that is part of ADF 12.2.1 including the one that is part of ADF Essentials.  When a user authenticates, the user’s name is in the userPrincipal property of the external context of the application.  The ADF Controller is probably picking up that this is not null and not equal “anonymous” and deciding that it needs to initialize a UserProfile for the user.  The library with this class is adf-share-ca.jar which IS part of ADF Essentials, but the constructor for this class must be calling something that is unique to WLS, and not available in Glassfish.  So it fails.  It does not matter how the external context property is set.  I tried it with Spring Security, which is an alternative to standard JEE authentication, but still does set the external context.  It had the same problem.

As it stands now, unless the ADF developers listen to our pleas to fix this, it is not possible to use authentication and authorization in an ADF Essentials 12.2.1.x application.  At least, it is not possible with an out-of-the-box deployment of the ADF Essentials libraries.  In my next post, I will detail a work-around.

Tuesday, February 28, 2017

Same blog, new location

This is the continuation of my blog at JJFlash's Oracle Development Journal - the story of an old developer learning new tricks.  I'll be posting here odds and ends about Relational Database design and development, especially Oracle RDBMS, Oracle Application Development Framework, Java, and whatever else comes to my mind as an IT expert.

I hope you enjoy it.