Friday, July 1, 2011

Oracle WCI Multilanguage Portlets

One of the cool things with the Oracle WCI Portal (aka BEA ALUI, Plumtree) is that it ships with the source code of the UI, which gives you the opportunity to re-write the UI. Using this you can also modify some of the basic portal functionalities like for example how the portlets are loaded. You can find the class responsible for loading the portlet in the namespace com.plumtree.portalpages.browsing.myportal and the name of the class is MyPortalContentView.

Now let’s say you do have a use case where the user is able to switch the language inside the portal and you do want to load the portlets depending on the user current language. You can localize the names of the portlet by going to the portlet properties and names and then select Support Localized Names, like shown on the screen bellow:

image

For this example I create 3 community links portlets and localized them on different languages. Now I want to change the portal code to load only the portlets which have localized name in the current user language. To do so I have to override the MyPortalContentView. Here is the code for how to do it:

1 import com.plumtree.openlog.OpenLogService;
2 import com.plumtree.openlog.OpenLogger;
3 import com.plumtree.portalpages.browsing.myportal.IMyPortalModelRO;
4 import com.plumtree.portalpages.browsing.myportal.MyPortalContentView;
5 import com.plumtree.portaluiinfrastructure.statichelpers.PTDebugHelpers;
6 import com.plumtree.server.IPTGadget;
7 import com.plumtree.server.IPTSession;
8 import com.plumtree.uiinfrastructure.activityspace.AActivitySpace;
9 import com.plumtree.uiinfrastructure.activityspace.IModel;
10 import com.plumtree.uiinfrastructure.activityspace.IModelRO;
11 import com.plumtree.xpshared.htmlelements.HTMLElementCollection;
12
13 /**
14 * Override the standard portal container view, show now only portlets localized to the current user language.
15 *
16 * @author L.Pelov
17 */
18 public class MyAppPortalContentView extends MyPortalContentView {
19
20 private static OpenLogger log = OpenLogService.GetLogger(OpenLogService
21 .GetComponent(PTDebugHelpers.COMPONENT_PORTAL_BROWSING),
22 "mydemo.portalpages.browsing.myportal.MyAppPortalContentView");
23
24 /**
25 * This function checks if portlet is localized to the current user language
26 *
27 * @param portletIndex
28 * @return true if the portlet is localized to current user language, otherwise false
29 */
30 protected boolean isPortletLocalized(int portletIndex) {
31
32 int iPortletID = m_asModel.GetPortletIDFromIndex(portletIndex);
33
34 // opens the portlet without to lock it!
35 IPTGadget portlet = (IPTGadget) ((IPTSession) m_asOwner.GetUserSession()).GetGadgets().Open(
36 iPortletID, false);
37
38 // get the current local language
39 String currLocale = m_asOwner.GetLocale();
40
41 if (currLocale.indexOf(portlet.GetPrimaryLang()) > -1) {
42 // isLocalized = true;
43 return true;
44 }
45 else {
46 boolean isLocales = portlet.GetIsLocalized();
47 if (isLocales) {
48 Object[][] arLocalNames = portlet.GetLocalizedNames();
49
50 // Get the available languages
51 if (arLocalNames != null && arLocalNames[0] != null && arLocalNames.length == 2) {
52 for (int cnt = 0; cnt < arLocalNames[0].length; cnt++) {
53 if (arLocalNames[0][cnt] != null) {
54 if (currLocale.indexOf(arLocalNames[0][cnt].toString()) > -1) {
55 // isLocalized = true;
56 // break;
57 return true;
58 }
59 }
60 }
61 }
62 }
63 }
64
65 return false;
66 }
67
68 /**
69 * @param nColumnID
70 * The ID of the column this portlet is currently in.
71 * @param nPortletIndex
72 *
73 * @return a HTMLElementCollection containing the entire portlet including the portlet header and content.
74 */
75 public HTMLElementCollection DisplaySinglePortlet(int nColumnID, int portletIndex) {
76
77 // if this portlet is not localized then just exit
78 if (!this.isPortletLocalized(portletIndex)) {
79 return new HTMLElementCollection();
80 }
81
82 return super.DisplaySinglePortlet(nColumnID, portletIndex);
83
84 }
85
86 /**
87 * Displays portlet content like the DisplaySinglePortlet function, but it is most used by the PTTAGs
88 *
89 * @param nColumnID
90 * The ID of the column this portlet is currently in.
91 * @param nPortletIndex
92 *
93 * @return a HTMLElementCollection containing the portlet body/content.
94 */
95 public HTMLElementCollection DisplaySinglePortletContent(int nColumnID, int portletIndex) {
96 // L.Pelov - make sure for later if you use Adaptive Tags that they will work in the same way
97 // if this portlet is not localized then just exit
98 if (!this.isPortletLocalized(portletIndex)) {
99 return new HTMLElementCollection();
100 }
101
102 return super.DisplaySinglePortletContent(nColumnID, portletIndex);
103 }
104
105 /** Parent Activity Space */
106 private AActivitySpace m_asOwner;
107
108 /** Read Only Model for MyPortal */
109 private IMyPortalModelRO m_asModel;
110
111 /**
112 * @see com.plumtree.uiinfrastructure.activityspace.IManagedObject#Create()
113 */
114 public Object Create() {
115 // L.Pelov - create from the subclass, not from the main one, to make sure that the original view will
116 // be replaced!
117 return new MyAppPortalContentView();
118 }
119
120 /**
121 * @see com.plumtree.xpshared.activityspace.IView#GetName()
122 */
123 public String GetName() {
124 return STR_MVC_CLASS_NAME;
125 }
126
127 /**
128 * @see com.plumtree.xpshared.activityspace.IView#Init(IModel, AActivitySpace)
129 */
130 public void Init(IModelRO model, AActivitySpace parent) {
131 log.Info("Init MyAppPortalContentView()");
132
133 m_asModel = (IMyPortalModelRO) model;
134 m_asOwner = parent;
135
136 // L.Pelov - IMPORTANT: you have to init also the main view otherwise you will get
137 // NullPointerException!
138 super.Init(model, parent);
139 }
140
141 }
142

Now several changes are made here. I add new function calls isPortletLocalized() which checks if portlet has been localized to current user language. If YES then the portlet show the portlet, if not then skip it.


Also as you can see from the code and I just override the function but after I check the if portlet should be load and call again the subclass method. This ensures that after you upgrade portal, even if it’s new functionality into the original method this code should work, except of course the Portal Server API has been change. It is of course best practices of course to test the code again when you upgrade to make sure that everything works well.


cheers

No comments:

Post a Comment