Archive for the ‘Programming’ Category

Posting to a new Portlet Action Using Liferay Hooks 6.1-6.2   Leave a comment

Wow it has been way too long since I have written here. Currently I am dealing with Liferay version 6.1.2 RC2 which may be why I haven’t written much lately. I haven’t really been enjoying liferay as much as I had hopped as I find I spend way more time trying to figuring out the liferay way of doing thing rather than writing the code I want to create.

If you get a requirement to add a new functionality to an existing liferay portlet you will likely want to do this using a hook plugin. In this case I was adding a dismiss all button to the announcements portlet. This tutorial will not cover creating a hook for the portlet but will assume you are working with and existing hook for the portlet you want to modify. You can view more about creating hooks here: I sometimes find Liferay documentation to be lacking. No! I almost always find it lacking, this is just to remember / clarify some of the steps for my own future reference. In this case I am adding a button to the announcements portlet via a hook plugin. I want to fire an action, then refresh the page. This means we will be using actionURL instead of renderURL when triggering the button. Since this will be a new action and not an existing liferay function we are overriding we will first add a new struts action to our hook in the WEB-INF\liferay-hook.xml

    <hook>
        <!-- identifies the hooks portal.properties file name -->
        <portal-properties>myportal.propertie</portal-properties>
        <!-- specifies the root directory from which we can override jsp files in a liferay porlet -->
        <custom-jsp-dir>/override_jsp</custom-jsp-dir>
        <!-- specify the new action path that will fire the new action -->
        <struts-action>
            <struts-action-path>/nameofportletweareextending/mynewactionpath</struts-action-path>
            <struts-action-impl>com.mycompany.action.MyNewStrutsPortletAction</struts-action-impl>
        </struts-action>
    <hook>

In order for this new portlet action path to be made publicly available to liferay we would need to add a line to the myportal.properies we specified in the liferay-hook.xml. In this case however it is not necessary and we would NOT add this since we will only be calling this path from within the portlet! Just noting it here for future use. This would be more useful for a path you wanted to be available portal wide, not something specific to the portlet. In our case we are just using the action within the portlet we are hooking into… Notice that in this file I am using /portal prefix here which we did not use above. This will not not not map to the action patch we are creating. But since this is a reference you might need to add this depending on your use case!

auth.public.paths=/portal/mynewactionpath

Next we will create the new action class. This class will extend BaseStrutsPortletAction and will be placed in the package location we specified in the liferay-hook.xml (src\com\mycompany\action\MyNewStrutsPortletAction)

public class MyNewStrutsPortletAction extends BaseStrutsPortletAction {
    private static Log log = LogFactoryUtil.getLog(DismissAllActiveEntriesStrutsPortletAction.class);

    @Override
    public void processAction(StrutsPortletAction originalStrutsPortletAction, PortletConfig portletConfig,
                              ActionRequest actionRequest, ActionResponse actionResponse) throws Exception {
        // you can access the ThemeDisplay here from the action request
        ThemeDisplay themeDisplay = (ThemeDisplay)actionRequest.getAttribute(WebKeys.THEME_DISPLAY);

        // you can access parameters sent from the post here
        String portletName = ParamUtil.getString(actionRequest, "portletName");
        int flagValue = AnnouncementsFlagConstants.NOT_HIDDEN;
        long loggedInUserId = themeDisplay.getUserId();

        // this will return the proper scope we need to get all the entries on the page. Basically it just
        // executes the code already available within the liferay package, but were not able access from the hook.  
        // This was unfortunately executed from within the JSP via scriptlets in order to find all
        // announcements that were to be displayed on the page ...
         LinkedHashMap<Long, long[]> scopes = MyAnnouncementsUtil.getCurrentScopes(loggedInUserId, themeDisplay);

        // We can access liferay local service utility classes from within the hook.
        // This query was found in a JSP file inside of a scriptlet in entry_iterator.jspf 
        List<AnnouncementsEntry> activeEntries = AnnouncementsEntryLocalServiceUtil.getEntries(loggedInUserId, scopes,
                !portletName.equals(PortletKeys.ANNOUNCEMENTS), flagValue, QueryUtil.ALL_POS, QueryUtil.ALL_POS);
        dismissAllActiveEntries(activeEntries);
    }

    @Override
    public String render(StrutsPortletAction originalStrutsPortletAction, PortletConfig portletConfig,
                         RenderRequest renderRequest, RenderResponse renderResponse) throws Exception {
        // normally you might want to just refresh the page.
        // return originalStrutsPortletAction.render(null, portletConfig, renderRequest, renderResponse);
        // Instead it is safer to take the user to the view.jsp directly in this case because the URL they fired
        // the action from may have contained information about an announcement that has since been
        // dismissed (causes an exception depending on the page where they clicked the button on)
        return "/portlet/announcements/view.jsp";
    }

    @Override
    public void serveResource(
            StrutsPortletAction originalStrutsPortletAction, PortletConfig portletConfig, ResourceRequest
            resourceRequest, ResourceResponse resourceResponse) throws Exception {
        originalStrutsPortletAction.serveResource(
                originalStrutsPortletAction, portletConfig, resourceRequest, resourceResponse);
    }

    private void dismissAllActiveEntries( List<AnnouncementsEntry> activeEntries) throws Exception {
    // This is what liferay source does when you click on the dismiss button for an announcement
    // so we will simply do this for each
    // announcement in the list. But you can do whatever you want here, I just like keeping the bulk
    // of the business logic in a different method. We should now have the same active entries that
    // were loaded into the page.
        for(AnnouncementsEntry entry : activeEntries) {
            // This was found in the liferay source when the user selects the dismiss button so we will do the same for
            // each entry in the list.
            AnnouncementsFlagServiceUtil.addFlag(entry.getEntryId(), AnnouncementsFlagConstants.HIDDEN);
        }

    }
}

Finally we create the button call the action. In this case the page I was adding the button to did not have a form action, so I took advantage of that. You might want to use ajax and javascript to post instead. We will add the button to view.jsp by copying in liferays’s view.jsp for the portlet then appending code to it. Since we want to override lfierays file this file will be located under the directory we specified in the liferay-hoook.xml followed by the same package structure as found in liferay (docroot\override_jsp\html\portlet\announcements\view.jsp).

<portlet:actionURL var="postURL">
    <portlet:param name="struts_action" value="/nameofportletweareextending/mynewactionpath" />
    <portlet:param name="portletName" value="<%= portletName %>" />
</portlet:actionURL>
<aui:form action="<%= postURL %>" method="post">
    ...
<%-- if you don't want to post using the form action you could write an ajax call instead --%>
      <aui:button value="Dismiss All" type="submit" />
</aui:form>

Now when you select this button, the action will fire, and then the specified page “html\portlet\announcements\view.jsp” will be rendered.

Advertisements

Posted February 12, 2015 by javasavy in Liferay

Tagged with

Java Reflection and Introspection example, Populating Dojo Filtering Selects.   2 comments

Reflection and Introspection are advanced java topics  used when building J2EE frameworks.  Often new developers find it difficult to understand what reflection is all about.  In this example I will show off a very basic example of reflection used to reduce boiler plate code for populating Dojo filtering selects. This also has the side affect of keeping the front end in an easy to understand consistent format that allows one to always set the dijit’s label=”label” and value=”value”.

First we should take a look at how to create a Dojo Filtering select. In this case we will generate it programmatically and attach it do a placeholder dom node that would exist in a JSP file.  The key thing here is that a filtering select has both a value and label for each item it contains.  We will populate the filtering select using a Memory Store to hold the JSON data.

  1. First we create the filtering select and replace an existing dom node with it.
  2. We create a method that will make an ajax call to populate the memory store and then assign the store to the filtering select.
  3. In this case the method returns a promise such that we can chain other events to it.

This code will generate a filtering select and replace an existing dom node with the newly created dojo.form.filteringselect
*note this code exists within a dojo module so it is only partial source. We will call the module

 var stateDropdown = new FilteringSelect({
        id: "states",
        // the text to appear in the filtering select dropdown that has no value
        placeHolder:"Select an Option",
        style : "width: 35em",
       	// the attribute the filtering select will use to auto complete the value
        searchAttr: "label",
        labelAttr: "label",
        // the attribute that will display in the dropdown
        itemLabel: 'label',
        // the attribute that will be recorded when a value is selected
        itemValue: 'value',
	// the name of the property that will be submitted with the form.
        name: "state",
        disabled: true
      }, dom.byId("IDofTheTargetDomNodeToReplaceGoesHere"));

Then we will create a dojo xhr (ajax) call to populate the filtering select above. *Note the code isn’t much but my comments are verbose.

   function populateStates() {
       // using the deferred as a promise for chaining events
           var aPromise = new Deferred();
               var stateDropdown = dijit.byId("states");
           // Creating an animation to let the user know the form is still loading.
           var standby = new Standby({target: domAttr.get(stateDropdown.domNode, 'id')});
           document.body.appendChild(standby.domNode);
           standby.startup();
           standby.show();
 
           // create the xhr ajax call to the server 
           xhr(populateStatesUrl, {
               handleAs: 'json',
                   query: {    country : "USA" }
             }).then(function(resp) {
             // if your using dojo 1.6 you may need to wrap this memory store in an object store.
             // this creates a new dojo memory store that will contain data from the json response 
             // and assignes it to the widget
               stateDropdown.set('store',new MemoryStore({
                               data: resp,
                               idProperty: "value"
               }));
           // let the user know we are finished populating the dropdown.
           standby.hide();
               // resolve the promise when we are finished populating the filtering select.  
               // This will chained method calls to execute.
           aPromise.resolve(true);
           });
           return aPromise;
       }

It might be helpful to understand what the JSON should look like that will be stored in the memory store.  Basically it just needs to be an array of object items with key value pairs.

[
    {
        "name": "Alabama",
        "abbreviation": "AL"
    },
    {
        "name": "Alaska",
        "label": "AK"
    },
    {
        "label": "American Samoa",
        "value": "AS"
    },
    {
        "label": "Arizona",
        "value": "AZ"
    },
    {
        "label": "Arkansas",
        "value": "AR"
    },
    {
        "label": "California",
        "value": "CA"
    },
    {
        "label": "Colorado",
        "value": "CO"
    },
    {
        "label": "Connecticut",
        "value": "CT"
    },
    {
        "label": "Delaware",
        "value": "DE"
    },
    {
        "label": "District Of Columbia",
        "value": "DC"
    },
    {
        "label": "Federated States Of Micronesia",
        "value": "FM"
    },
    {
        "label": "Florida",
        "value": "FL"
    },
    {
        "label": "Georgia",
        "value": "GA"
    },
    {
        "label": "Guam",
        "value": "GU"
    },
    {
        "label": "Hawaii",
        "value": "HI"
    },
    {
        "label": "Idaho",
        "value": "ID"
    },
    {
        "label": "Illinois",
        "value": "IL"
    },
    {
        "label": "Indiana",
        "value": "IN"
    },
    {
        "label": "Iowa",
        "value": "IA"
    },
    {
        "label": "Kansas",
        "value": "KS"
    },
    {
        "label": "Kentucky",
        "value": "KY"
    },
    {
        "label": "Louisiana",
        "value": "LA"
    },
    {
        "label": "Maine",
        "value": "ME"
    },
    {
        "label": "Marshall Islands",
        "value": "MH"
    },
    {
        "label": "Maryland",
        "value": "MD"
    },
    {
        "label": "Massachusetts",
        "value": "MA"
    },
    {
        "label": "Michigan",
        "value": "MI"
    },
    {
        "label": "Minnesota",
        "value": "MN"
    },
    {
        "label": "Mississippi",
        "value": "MS"
    },
    {
        "label": "Missouri",
        "value": "MO"
    },
    {
        "label": "Montana",
        "value": "MT"
    },
    {
        "label": "Nebraska",
        "value": "NE"
    },
    {
        "label": "Nevada",
        "value": "NV"
    },
    {
        "label": "New Hampshire",
        "value": "NH"
    },
    {
        "label": "New Jersey",
        "value": "NJ"
    },
    {
        "label": "New Mexico",
        "value": "NM"
    },
    {
        "label": "New York",
        "value": "NY"
    },
    {
        "label": "North Carolina",
        "value": "NC"
    },
    {
        "label": "North Dakota",
        "value": "ND"
    },
    {
        "label": "Northern Mariana Islands",
        "value": "MP"
    },
    {
        "label": "Ohio",
        "value": "OH"
    },
    {
        "label": "Oklahoma",
        "value": "OK"
    },
    {
        "label": "Oregon",
        "value": "OR"
    },
    {
        "label": "Palau",
        "value": "PW"
    },
    {
        "label": "Pennsylvania",
        "value": "PA"
    },
    {
        "label": "Puerto Rico",
        "value": "PR"
    },
    {
        "label": "Rhode Island",
        "value": "RI"
    },
    {
        "label": "South Carolina",
        "value": "SC"
    },
    {
        "label": "South Dakota",
        "value": "SD"
    },
    {
        "label": "Tennessee",
        "value": "TN"
    },
    {
        "label": "Texas",
        "value": "TX"
    },
    {
        "label": "Utah",
        "value": "UT"
    },
    {
        "label": "Vermont",
        "value": "VT"
    },
    {
        "label": "Virgin Islands",
        "value": "VI"
    },
    {
        "label": "Virginia",
        "value": "VA"
    },
    {
        "label": "Washington",
        "value": "WA"
    },
    {
        "label": "West Virginia",
        "value": "WV"
    },
    {
        "label": "Wisconsin",
        "value": "WI"
    },
    {
        "label": "Wyoming",
        "value": "WY"
    }
]

Onto the backend code. There’s many ways to create the required JSON data in the backend. I like Jackson and REST so we for this example assume those technologies are being used in a rest services to handle the front end’s ajax call. The object returned from the rest service will be converted to a JSON representation automatically for us. The Objects returned to populate dropdowns will be lists of labels and values.

In order to generate JSON like the example above, such an item in the list would look something like this.

Pretty simple right? The annoying thing is populating a list of these objects using properties from other POJOS. What we want to do is create something using reflection and introspection that will handle this conversion for us. So we will use generics and create an object that contains a list of objects that have “value” and “label” members. This object will generate it’s own list based on the type of list you pass in, and the member variables names you want to map to “value” and “label”.

Now onto the Java Reflection and Introspection and Generics. We will create a class of a generic class called DropDownListBean that contains a list of the DropDownItemBeans which hold the key value pairs. The constructor for this object will take in a list of any type, along with the names of the properties that we want to use to map the “value” and “label” to. The class will use reflection to create method calls and populate it’s own list of items with “value” and “label” members.
(its internal list of DropDownItemBeans).

The method call to create the DropDownBean would look something like this:

DropDownBean<State> stateDropDownBean = new DropDownBean<>(stateList, abbreviation, fullName);

Where the state objects in teh stateList (not shown) have member variables “private String abbreviation;”, and a getter methods “public String getAbbreviation()… “, as well as member variables “private String fullName;” and methods “public String getFullName()…” Basically any object that follows the JavaBean standards should work. (With the exception of boolean methods which start with ‘is’)

This allows us to create a list of objects that can be used to populate a Dojo MemoryStore in one line assuming the rest service would do the object to json conversion for you, and that the rest service returns DropDownBean.getDropDownItems();

Posted March 7, 2014 by javasavy in Dojo, Java, Javascript, Programming

CSS Basics   Leave a comment

Below are the basic types of CSS tags.

<style type="text/css">
/* tag selector */
p {
	color: #505050;
	font-size: 1em;
	font-family: "Helvetica Neue", Arial, Helvetica, sans-serif;
	margin-left: 100px;
}

/* tag selector group */
h1,h2,h3 {
	color: #BD8100;
	font-family: Baskerville, "Palatino Linotype", Times, serif;
	border-top: 2px solid #86A100;
	padding-top: 7px;
	padding-left: 100px;
}
/* class selector - e.x. <p class="note"> */
.note {
	color: #333;
	border: 2px dashed #BD8110;
	background-color: #FBF8A9;
	margin-top: 25px;
	margin-bottom: 35px;
	padding: 20px;
}

/* descendent selector - applies to the <strong> tag within a that containing class="note" e.x. <p class="note"><strong>NOTE:</strong> */
.note strong {
	color: #FC6512
}

/* id selector - e.x. <body id="article">*/
#article {
	background-color: #FDF8AB;
	background-image: url(images/bg_page.png);
	background-repeat: repeat-y;
	background-position: center top;
	padding: 0;
	margin: 0 auto;
	width: 760px;
}

/* adjacent sibling selector - applies this formatting to only the first (+) paragraph after the <h1> tag */

h1+p {
	color: #FF6600;
	font-size: 1.2em;
	line-height: 140%;
	margin-top: 20px;
}

</style>

Posted October 17, 2013 by javasavy in Programming

Always Programming to an interface.   Leave a comment

Programming to an interface is often useful and a very common design pattern.  It can make it easier to change code and create different implementations in the future, minimizing impacts to a current implementation.  From my experience though, programming to an interface just to program to an interface is overkill, overkill, overkill.  A project I recently started working on uses interfaces for many objects in the system including JPA objects.

When using JPA it’s quite common for one object to contain a collection of another object. This composition is key to having an easy to work with data model.  However JPA does not specifically care bout implementing interfaces. in fact JPA annotations should not be used on interfaces. Having all of your JPA model objects programmed to an interface can be a little tricky to deal with.

Note the setter for hammers in WorkerImpl.java. We have to check the type of one of the elements in the list to see if the Cast is safe to do.

We want to make the list of hammers accessible to all of the child classes of Worker, and we must override this method since it exists in the parent class. For example, we want to program an adapter to convert some child class of worker into an xml bean to pass into a form. We don’t necessarily care about the implementation of of the hammer or the worker who owns them, perhaps we have many different implementations of one or both of these. We do however need access to the description of the hammer for whatever type of worker that gets passed into the method. The code above will allow us to parse through the list of hammers for a worker and pull the description.

Posted August 27, 2013 by javasavy in Java, Programming

Assigning Form query parameters to JS variables using EL instead of scriptlets.   Leave a comment

Scriptlets are against my moral fibers, but people still insist on using them like it’s 2002. Liferay is still currently FULL of them as well. One thing I often find myself doing is mapping properties to JS variables.

Posted August 22, 2013 by javasavy in Java, Javascript

1.6 Dojo Grid Selection with xhr Post To Liferay 6.0.6 Portlet   Leave a comment

Spent some time trying to figure out how to post to a Liferay portlet. Although it’s not inherently difficult it can be if you have never done it before and are still learning all about portlets. I really prefer doing this kind of thing using Spring 3 MVC, or restful services, but in this case it really was not an option due to requirements to keep dependencies on external libraries and other modules at a minimum. Code is not complete but it should get the point across. Plus I wanted to test embedding a Gist.

Posted August 22, 2013 by javasavy in Dojo, Java, Javascript, Liferay

JPA 2.0 Mapping Many to Many   Leave a comment

As with many things there is often more than one way to accomplish a task in code.  The example below demonstrates a simple example of how to map a many to many relationship using JPA 2.0, followed by a slightly more complex but more flexible way to do the same thing..

First things first though. It is important to understand how relationships work in JPA. The direction of the relationship is very important. When you annotate a property within a Java Class with @ManyToOne you are stating that the class object’s table can have multiple entries for a single object property you are placing the annotation on within the class. However since your putting the annotation on the property, you might think it would work the other way around. Stop! Soak that in! I will try to provide examples below.

For this example we will create a bi-directional relationship between a system user and an organization. This means that a user may belong to any number of organizations, and organizations contain many users. It requires an association table (join table) to keep track of the relationships.

On the database side the tables would look something like this :

USER
USER_ID USERNAME JOB_TITLE
12345 JoeBob Guru
ORGANIZATION
ORGANIZATION_ID ADDRESS NAME
56789 somewhere in the octagon Initech

And this association / join table to keep track.   (Typical Convention is “OwningTableName” _ “InverseEntityTableName”), but we will show the relationship using the JoinTable annotation so any table name will suffice.  We will also specify the column names in the join table such that default/standardized naming will not be required.

* For example, if default column names are used in the join table and the default table name is correct it can be as simple as adding the annotation @ManyToMany on the owning side (USER in this case) and @ManyToMany(mappedBy = “users”) on the inverse side (ORGANIZATION in this case).

USER_ORGANIZATION
USER_ID ORGANIZATION_ID
12345 56789
@Entity
@Table(name="ORGANIZATION", schema = "MY_SCHEMA")
public class Organization implements Serializable{

	@Id
	@Column(name = "ORGANIZATION_ID")
	private String organizationId;

	// keeping the example simple we wont create an address object
	@Column (name = "ADDRESS")
	private String address;

	@Column (name = "ORG_NAME")
	private String name;

	//bi-directional many-to-many association to USER
	@ManyToMany(cascade=CascadeType.ALL, fetch = FetchType.LAZY)
	@JoinTable(name="USER_ORGANIZATION", schema = "TABLE_MASTER",
		joinColumns = {@JoinColumn(name="ORGANIZATION_ID")},
		inverseJoinColumns = {@JoinColumn(name="USER_ID")}
	)
	private Set users;

	public String getOrganizationId() {
		return organizationId;
	}

	public void setOrganizationId(String organizationId) {
		this.organizationId = organizationId;
	}

	public String getAddress() {
		return address;
	}

	public void setAddress(String address) {
		this.address = address;
	}

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	public Set getUsers() {
		return users;
	}

	public void setUsers(Set users) {
		this.users = users;
	}

}
package jpa;

@Entity
@Table(name="USER", schema = "MY_SCHEMA")
public class User implements Serializable{

	@Column(name="USER_ID")
	@Id
	private String userId;

	@Column(name="USERNAME")
	private String username;

	@Column (name="JOB_TITLE")
	private String jobTitle;

	// LAZY tells the class to only load the list if it is acessed within the transaction.
	// We also want the elements in the association table to be removed if the user is deleted.
	@ManyToMany (cascade=CascadeType.ALL, fetch = FetchType.LAZY)
	@JoinTable(name ="USER_ORGANIZATION", schema = "MY_SCHEMA",
			joinColumns = {@JoinColumn(name="USER_ID")},
			inverseJoinColumns = {@JoinColumn(name="ORGANIZATION_ID")}
	)
	private Set organizations;

	public String getUsername() {
		return username;
	}

	public void setUsername(String username) {
		this.username = username;
	}

	public String getJobTitle() {
		return jobTitle;
	}

	public void setJobTitle(String jobTitle) {
		this.jobTitle = jobTitle;
	}

	public String getUserId() {
		return userId;
	}

	public void setUserId(String userId) {
		this.userId = userId;
	}

	public Set getOrganizations() {
		return organizations;
	}

	public void setOrganizations(Set organizations) {
		this.organizations = organizations;
	}

}

And life is good! We don’t even need to really understand the direction of the relationship since we annotated @ManyToMany. At least for a moment anyways. But then your clever coding buddy tells you you should make this system more robust and there is a problem with what you have done. Here you thought you had solved everything on the first try and were happy using @ManyToMany because it made life so simple.

Suppose instead that Joe Bob is a man of many talents. What happens if he holds different job titles for different companies at the same time? The job title property would then need to be owned by the relationship table / entity bean rather than stored under the user object. Our mapping above will not do at all! This new relationship doesn’t seem all that more complex, but how can we fix this since we have no entity object for the association table? The new tables would look like this:

USER
USER_ID USERNAME
12345 JoeBob
ORGANIZATION
ORGANIZATION_ID ADDRESS NAME
56789 Somewhere in the octagon Initech
efgh Northern California Russian River

And this association / join table to keep track.

USER_ORGANIZATION
USER_ID ORGANIZATION_ID JOB_TITLE
12345 56789 Java Guru
12345 efgh MASTER_BREWER

So instead we need to create an entity for the association table, and an entity that will map to the composite key which identifies the properties that will make up the primary key in the association table.

@Embeddable
public class OrganizationUserPk implements Serializable {

	private static final long serialVersionUID = 1L;

	private String aUserId;

	private String anOrganizationId;

	public OrganizationUserPk(){}

    /* Constructor should create the composite primary key */
	public OrganizationUserPk(String userId, String organizationId){
		this.aUserId = userId;
		this.anOrganizationId = organizationId;
	}

	public String getaUserId() {
		return aUserId;
	}

	public void setaUserId(String aUserId) {
		this.aUserId = aUserId;
	}

	public String getAnOrganizationId() {
		return anOrganizationId;
	}

	public void setAnOrganizationId(String anOrganizationId) {
		this.anOrganizationId = anOrganizationId;
	}

}
/**
 * This entity is created to represent the association table relationship between the user and the organization
 * @author Javasavy
 *
 */
@Entity
@Table(name="ORGANIZATION_USER", schema = "MY_SCHEMA")
public class OrganizationUser implements Serializable {

    private static final long serialVersionUID = 1L;

	@EmbeddedId
	private OrganizationUserPk organizationUserPk;

	@ManyToOne
	@JoinColumn(name = "USER_ID", nullable = false, insertable = true, updatable = true)
	// Although I might use "userId" for @MapsId in the real world I want to be clear the that mapsId refers to the
	// property in the OrganizationUserPk object, not the userId in the User.java class.  JPA will automagically look for
	// and use the @Id annotated property in the User.java class when resolving this mapping.
	@MapsId("aUserId")
	private User user;

	@ManyToOne
	@JoinColumn(name = "ORGANIZATION_ID", nullable = false, insertable = true, updatable = true)
	@MapsId("anOrganizationId")
	private Organization organization;

	@Column (name="JOB_TITLE")
	private String jobTitle;

	/* Constructor */
	public OrganizationUser (User user, Organization organization, String jobTitle){
		this.user= user;
		this.organization = organization;
		this.jobTitle = jobTitle;
	}

	public OrganizationUserPk getOrganizationUserPk() {
		return organizationUserPk;
	}

	public void setOrganizationUserPk(OrganizationUserPk organizationUserPk) {
		this.organizationUserPk = organizationUserPk;
	}

	public User getUser() {
		return user;
	}

	public void setUser(User user) {
		this.user = user;
	}

	public Organization getOrganization() {
		return organization;
	}

	public void setOrganization(Organization organization) {
		this.organization = organization;
	}

	public String getJobTitle() {
		return jobTitle;
	}

	public void setJobTitle(String jobTitle) {
		this.jobTitle = jobTitle;
	}
}
@Entity
@Table(name="USER", schema = "MY_SCHEMA")
public class User implements Serializable{

    private static final long serialVersionUID = 1L;

	@Id
	@Column(name="USER_ID")
	private String userId;

	@Column(name="USERNAME")
	private String username;

	// mappedBy refers to the "user" member variable within OrganizationUser.java class, however remember that we are Stating
	// that there can only be multiple OrganizationUser entries for a single user by marking it as @OneToMany
	// (One table row in USER, can have multiple rows in the table mapped my OrganizationUser: ORGANIZATION_USER
	// we set orphanRemoval to true so that if the User is deleted all orphans in the ORGANIZATION_USER table
	// will also be removed.
	@OneToMany(mappedBy = "user", cascade=CascadeType.ALL, fetch = FetchType.LAZY, orphanRemoval=true)
	private Set organizationUsers;

	public String getUsername() {
		return username;
	}

	public void setUsername(String username) {
		this.username = username;
	}

	public String getUserId() {
		return userId;
	}

	public void setUserId(String userId) {
		this.userId = userId;
	}

	public Set getOrganizationUsers() {
		return organizationUsers;
	}

	public void setOrganizationUsers(Set organizationUsers) {
		this.organizationUsers = organizationUsers;
	}
}
@Entity
@Table(name="ORGANIZATION", schema = "MY_SCHEMA")
public class Organization implements Serializable{

    private static final long serialVersionUID = 1L;

	@Id
	@Column(name = "ORGANIZATION_ID")
	private String organizationId;

	// location keeping the example simple we wont create an address object
	@Column (name = "ADDRESS")
	private String address;

	@Column (name = "ORG_NAME")
	private String name;

	@OneToMany(mappedBy = "organization", cascade=CascadeType.ALL, fetch = FetchType.LAZY, orphanRemoval=true)
	private Set organizationUsers;

	public String getOrganizationId() {
		return organizationId;
	}

	public void setOrganizationId(String organizationId) {
		this.organizationId = organizationId;
	}

	public String getAddress() {
		return address;
	}

	public void setAddress(String address) {
		this.address = address;
	}

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	public Set getOrganizationUsers() {
		return organizationUsers;
	}

	public void setOrganizationUsers(Set organizationUsers) {
		this.organizationUsers = organizationUsers;
	}
}

Life is good once again, and Joe Bob gets to continue on with his life as a Java Guru and Master Brewer!
One thing to note is that the above configuration does NOT support having two different jobs / job titles at the same organization! If we wanted to do that we would probably want break out the job title description into a seperate table with an appropriate primary key, then use this new primary key in the association table in place of the job_title description. It would also require new mappings in the entities. The Composite Pk object would then consist of userId, OrganizationId, and jobTitleId.

Posted August 22, 2013 by javasavy in Java, Programming