Sometimes you just need to change ports. When I was a kid, it was the port of New York:

port-newyork-400.jpg

In search of love, I tried the port of Syndey (from which I supported a Plumtree portal system):

port-syndey-400.jpg

Later I found true love in the port of Seattle (from which I supported a BEA ALUI portal system):

port-seattle-400.jpg

And now the local port is San Francisco (from which I support an Oracle WCI portal system).

port-sanfran-400.jpg

And speaking of those portals and changing ports, sometimes you realize that your Configuration Manager service would suit you better if it ran on a different port. You can change the port by following these steps:

1. Remove the existing configuration manager service:

%PT_HOME%\configmgr\2.0\bin\configmgr.bat remove

2. Backup then edit %PT_HOME%\configmgr\2.0\settings\config\private.xml. Set the "EAS:httpsport" to the desired port.

3. Backup then edit %PT_HOME%\configmgr\2.0\settings\config\wrapper.conf. Edit the wrapper.ntservice.name and wrapper.ntservice.displayname to reflect the desired port.

4. Install the configuration manager service:

%PT_HOME%\configmgr\2.0\bin\configmgr.bat install

5. Start the configuration manager service.

Enjoy!



Tunings for the LDAP IDS Sync

| | Comments (0)
gone_running.jpgAre you worried about your LDAP IDS sync's running time? If your system is relatively small, you may not think much about it. You run them each night, or maybe even several times during the day, and life is good. However, on systems that push beyond several hundred thousand users, the performance of this product may become important. An obscure setting can cut the time in half.

This week I reinstalled the IDS, and after running it with default settings, my sync ran in about eight hours. After some tunings though, the job usually finishes in three and a half hours.

Cached Objects
The most important tuning done in %WCI_HOME%\ptldapaws\2.2\settings\config\ldap\properties.xml. I increased the MAX_CACHED_USER_OBJECTS setting from the meager 20000 to instead 1000000.

Memory
With this increased cache setting, you may also find you need to increase memory allocation. Do this in
%WCI_HOME%\ptldapaws\2.2\settings\config\wrapper.conf:

# Initial Java Heap Size (in MB)
wrapper.java.initmemory=1024

# Maximum Java Heap Size (in MB)
wrapper.java.maxmemory=1024

Session Timeout
Another tuning we use that may be necessary when you run larger synchronization batches is to increase the session timeout period within the ldapws.war file's web.xml. The default session-timeout is 60 minutes, but we run at 600.

Enjoy!

A Secret to Install Pandora on Blackberry

| | Comments (0)
pandora_blackberry.pngTo my normal readers, don't worry! This blog will soon return to its regular programming!

While installing Pandora on my Blackberry Pearl, I hit an obscure error message. Google only knew of a single page in the whole wide world wide web that discussed this error, but that page had no solution. So now for the perfect stranger who came here from Google, who doesn't care about Oracle software, who doesn't know me, and who just wants to listen to his or her reggae/polka/rap/country/classical music through the Blackberry, I bring you this special announcement:

Pandora provides different application downloads based on which device it thinks you're using, and it determines your device by your browser's emulation mode. So if you're not using the Blackberry emulation mode, then your device may try to download the wrong one. In my case, I saw the error "Unsupported media type: application/x-cabinet," and the device wanted to download pandora.cab. I was using MS Pocket IE mode when that happened. You may be using a different but still wrong mode, so try setting it properly. To do so:

  1. Open your browser (and it must be the default browser--don't try Opera Mini or some such thing)
  2. Click the Blackberry menu button
  3. Select "Options"
  4. Select "Browser Configuration"
  5. Set your emulation mode to Blackberry
  6. Navigate to http://www.pandora.com (or refresh if you had already been there)
  7. Download, and you'll be in business
  8. For good sound, use a headset of some sort
  9. Give me a comment if this really did help you
Enjoy!

Book Response: Curing their Ills

| | Comments (0)
curing.jpgI'm in an anthropology class called "The Politics of Humanitarianism," and I've just toppled one of its reading assignments. I tried posting a 140 character review on Twitter, but it wasn't successful--someone asked me to try again. Since the professor too requires more than just a tweet in response, I wrote up a couple pages. I share those here for Neema and for the rest of you portal junkies who need a break.

In Curing their Ills, Cambridge anthropologist Megan Vaughan examines the difficulties faced by African colonizers as they tried to find the best frame of reference from which to approach African medical problems. Colonizers struggled in their own debates to determine whether to perceive Africa and Africans in terms of difference as well as whether to attribute behaviors and outcomes to African culture or African nature. Vaughan conveys the idea of Jean Comaroff about biomedical knowledge that "whilst it is ostensibly based on 'empirical objectivity', in practice its underlying epistemology remains a 'cultural construct', existing in 'dialectical relationship with its wider social context'."[1] Though the colonizers may have had good intentions, it is problematic to transplant a cultural construct.

 

Vaughan explores "the African" as assumed by the medical community in the context of missionary medicine, leprosy, insanity, sexually transmitted disease, and didactic books and videos. A challenge with missionary medicine was how much the care providers should link physical health with spiritual health and "moral" practice. Perhaps no construct is as cultural as a religious one. An interesting aspect of dealing with African leprosy patients was that the colonizers seemed to view their primary identity as that of lepers and only their secondary identity as that of Africans. The problem with identifying insanity was that it was defined as an aberration from "normal" but normal African behaviors themselves were viewed as pathological by many colonizers. The growth (or at least persistence) of STDs was in part a result of the traditional African systems being destabilized by those introduced by European interaction, and some blamed it specifically on Christianity which hoped to introduce its own moral code in the place of the indigenous one. Regardless of the medical issue, the response would include propaganda of some sort, and this propaganda whether in the form of written material or film could not be created without first defining its audience and that audience's learning styles.

 

One response I had to the book was that when seen through an anthropologist's critical eye, a cultural boundary-crosser can enter a no-win situation. How shall the traveler interact with his host culture? To deny difference is to deny the other, but to perceive difference is to wade into alligator infested waters. Is it oppressive to even categorize another? Are stereotypes, useful shorthand in themselves, always unacceptable because of their generality rather than precision? If one cannot escape every influence of one's culture in making a judgment, then can the judgment withstand the scrutiny of a deconstructing anthropologist? Yes, colonialism is a concept with terrible connotations, but not everything related to it is terrible. Individuals, groups, nations, and cultures have asymmetric relationships, and within any asymmetric relationship is found the potential for abuse and is often found colonialism either in fact or in creative perception. However, such asymmetries and abuses existed within pre-colonial societies as well (no footnote on this). A key factor magnifying the disgraces of traditional colonialism as seen in Curing their Ills is that when cultures encounter each other, especially when one has new technologies, then change occurs. Change is often painful (e.g. for the Africans whose health deteriorated as they migrated to work locations in response to the globalizing economy) but in other cases the change alleviates problems (e.g. when transportation became available for the migrants).

 

Maybe I'm a bit defensive because I'm [1] white, [2] male, [3] involved in international humanitarian efforts, [4] religious, and [5] carrying a passport from the neocolonial power. In any case, this was a thought-provoking book, and I write my critique with a smile!



[1] Vaughan, Megan: Curing their Ills. Stanford University Press: Stanford CA; 1991: p 6.


lost-and-found.jpg

When you're working with servers behind a load balancer, do you ever feel a bit lost about which server you're really on? I do. With the ALUI/WCI portal pages, you can find an HTML comment telling you which server rendered the page. But today I realized it's hard to know which imageserver I'm on. So here's a little file to put on each website. Place it at http://myhostname/whereami.aspx, and you can hit it whenever you want to know which physical server you've been routed to by the load balancer.


<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<html xmlns="http://www.w3.org/1999/xhtml" >
<head id="Head1" runat="server">
<title>Machine: <%= System.Net.Dns.GetHostName() %>
- URL: <%= Request.Url.Host.ToString() %></title>
</head>
<body>
This is machine <b> <%= System.Net.Dns.GetHostName() %></b>.
<p>You came here on URL <b> <%= Request.Url.Host.ToString() %>.</b>
</body>
</html>

This would be simple in Java too, but I've not written it. Add it as a comment if you'd like?

Enjoy!

Why the Slowwwww API Searches?

| | Comments (0)
Last month I shared a diagnostic application for the WCI API Service. It worked great on my machine, but...

slow.snail.jpg

Performance was terrible when I deployed it to my customer's environment. It commonly would take 8 seconds (8300 ms) to load. Why the hang up? On my laptop it only took 20 ms.

I looked at the spy logs, and I found that nearly all the processing time went to this  command from the API Service when it tried querying users:

SQueryRequest.execute() executing query: "(((not null) TAG phraseQ OR null) AND ((subtype:"PTUSER")[0])) AND ((((@type:"PTPORTAL")[0]) OR ((@type:"PTCONTENTTEMPLATE")[0])) AND (((ptacl:"u1") OR (ptacl:"9994") OR (ptacl:"9992") OR (ptacl:"51") OR (ptacl:"1"))[0]) AND (((ptfacl:"u1") OR (ptfacl:"9994") OR (ptfacl:"9992") OR (ptfacl:"51") OR (ptfacl:"1"))[0])) METRIC logtf [1]"

The customer has 1.1 million users in the database, so maybe the search index is just very slow? I deleted a few hundred thousand users, and the query could then regularly return in about 6200 ms, so this was a major improvement. Also, I used the standard administrative UI to search for all users, and it took a similarly long time to return.

Ahh, so the problem is that the search index is doing a very bad job querying against a large set of objects.

Does anyone know whether there is a way to overcome this problem? Some uninspired attempts to tune the search service's cache size gave me no material change.

So in the absence of good tuning knowledge? I changed the apicheck diagnostic app so that now it verifies it can query communities (of which there are hundreds) instead of the users. The performance problems for my portlet have magically gone away




Over the past many releases of ALUI/WCI, I've been dragging a UI customization along to properly order subcommunities and related communities. Since it looks like the bug that my customization addresses won't be going away any time soon, I thought I'd share it.

In Plumtree 5.x, subcommunities and related communities displayed in alphabetical order. This made sense for humans, the predominant users of the portal. Once G6 was released though, this ordering was lost, and communities then ordered by object ID. This made sense for computers, but... what about the humans? I replaced the NavigationCommSectionDropDown view after putting in a bit of code that grabs the community objects and reorders them for humans.

Default UI
default.ordering.jpg

Human-Friendly UI (customized)
customized.ordering_human.friendly.jpg

You can download the code here. The download includes a diff showing how my code varies from the 6.x view it replaces. It also includes a diff showing the minor modifications between 6.x and 10g. Based on the apparent insignificance of the 10g changes, I continue to build the customized DLL based on the 6.x code. 

To deploy this customization, add the following to %WCI_HOME%\settings\portal\CustomActivitySpaces.xml:

<libfile name="subcommalphaorder"/>
Then copy the attached DLL to these locations:

%WCI_HOME%\ptportal\10.3.0\bin\assemblies\subcommalphaorder.dll
%WCI_HOME%\ptportal\10.3.0\webapp\portal\web\bin\subcommalphaorder.dll

Enjoy!

Unfortunately, WCI ships without providing an easy way to validate that the API service works properly. Some system administrators mistakenly believe the API service works if they see the message "Hi there, this is an AXIS service!" That message only confirms the service has been turned on and gives no information about whether it may have fatally failed at startup. To provide real health information for the API service, I've written the API Check application.

This application was tested on ALUI 6.1 and WCI 10gR3.

Contexts for Use

Portal administrators will most likely choose to run the API Check application within the WCI portal as a portlet. Portlet mode is always available when the API Check application is turned on. Some organizations will additionally wish to access the API Check application available outside the portal through its standalone mode. Standalone mode is most useful when the organization performs automated service monitoring such as for a load balancer and needs to see the status without logging into the portal.

Risks

In portlet mode, this application presents no security risks. The application will retrieve a login token from the portal's request allowing API Check to connect to the system as the calling user. This is the recommended approach. However, in standalone mode, there is a security risk because standalone mode requires a credential for a portal user be stored within the applications's web.xml file. This should be avoided when possible. If however you do choose to enable standalone mode, then be sure to use the credentials of a user with minimal rights to the portal. No special priviledges need be given to this account, and the account certainly should not have any administrative rights. The automated monitoring should scan for "DBQuerySuccess" to determine the service is up.

Install

This application runs adjacent to your existing %WCI_HOME%\ptws\10.3.0\webapp\ptapi.war file so that it will start and stop as the API service starts and stops. To install:
  • Place apicheck.war into the API service's webapps directory.
  • Import apicheck.pte into your portal. That PTE file is located within apicheck.war's install-resources directory. The PTE file will create an administrative folder, a community, a remote server, a web service, and a portlet for the API Check application.
  • From the portal admin interface, edit the API Check remote server to go to the proper address.
  • Browse to the API Check community to verify the portlet works.

Optionally, follow these additional steps if you wish to use the standalone mode:

  • Make sure you have the credentials for a portal-based user with low privileges in the portal.
  • Unpack apicheck.war
  • Edit WEB-INF\web.xml such that the values for username and userpass represent the low-rights account that should connect
  • Repack apicheck.war with the new web.xml file
  • Restart the API service
  • Browse to http://localhost:11905/apicheck/index.jsp to validate that it works.

Get the Code

This application is available for download here.

Note: The code was updated on March 20 09 to test the search API with a lookup of communities (fast) instead of users (potentially slow). Read more.

Enjoy!
API Check in Portlet Mode

 

API Check in Standalone Mode

An Invisible Portlet

| | Comments (2)
I had heard of them before, but I had never seen them: Invisible Portlets. Now I can write them.

It turns out there can be a decent use case for an invisible portlet. I wanted to put a stylesheet on a page through a portlet, but I didn't want to have to tweak any of the other portlets to do it. And since the only purpose of my portlet is to deliver a stylesheet, I didn't want the portlet to show up with a header or a title. Perhaps you'll want to use this approach to put some JavaScript on the page for tracking purposes. In any case, the code is pretty simple.

The concept is that when it displays on the page, each portlet object renders with a class ID to let you manipulate it directly. In some cases, you might change the font in the title bar, but in this case, I'm taking the entire region and making it invisible. If you set it invisible through display=none, then it will not be visible to the user, but JavaScript and style instruction still apply to the page.  I use the $$TOKEN$$ concept to access the portet object ID, and that is used in the class ID. Here it is:

<pt:namespace pt:token="$$TOKEN$$" 
xmlns:pt='http://www.plumtree.com/xmlschemas/ptui/'/> <script> alert("Portlet $$TOKEN$$ will magically disappear!"); document.getElementById('pt-portlet-$$TOKEN$$').style.display = 'none'; </script> <link type="text/css"
href="pt://images/plumtree/ptanalytics/private/css/colossus-en.css"
rel="StyleSheet" lang="en" ></link>
For demonstration purposes, that code includes an alert line that will cause the portlet to first notify you that it's really live on the page and then after you acknowledge it, it disappears. You will most likely want to customize the alert message by deleting it :-P

The code is live on this web server, so you can load it into your portal for a look if you'd like. Find it at http://blog.billbenac.com/code/disappearing.portlet.html.

Enjoy!

Update: A Better Approach

Thanks to Steve who pointed out a better way of getting the result I described above. He suggested setting the display to none in CSS directly rather than through JavaScript. That approach would look like this:

<pt:namespace pt:token="$$TOKEN$$" 
xmlns:pt='http://www.plumtree.com/xmlschemas/ptui/'/>

Portlet $$TOKEN$$ should be invisible through CSS.

<style>
#pt-portlet-$$TOKEN$$ { display:none; }
</style>

The title tells me this is going to be boring to some readers, but I guarantee those who arrive from Google searches will be glad for it--especially since an early discussion of this that used to be on forums.bea.com is now gone.

A funny problem arises when you take certain portlets written in .NET and load them into ALUI 6.5 or Oracle 10gR3 portals. The portlets at issue use the EDK/IDK's PRC library. Even though these portlets work fine when loaded into ALUI 6.1 portals, they suddenly fail with this deceptive message:

The underlying connection was closed: The server committed an HTTP protocol violation. at com.plumtree.remote.prc.soap.QueryInterfaceProcedures.GetVersionInfo() in e:\latestbuild\Release\devkit\5.4.x\prc\src\dotnet\portalprocedures\QueryInterfaceProcedures.cs:line 35 at com.plumtree.remote.prc.xp.XPRemoteSession.getAPIVersion() in e:\latestbuild\Release\devkit\5.4.x\prc\src\xpj2c\portalclient\com\plumtree\remote\prc\xp\XPRemoteSession.cs:line 352 at Plumtree.Remote.PRC.RemoteSessionWrapper.GetAPIVersion() in e:\latestbuild\Release\devkit\5.4.x\prc\src\dotnet\portalclient\RemoteSessionWrapper.cs:line 144 at apicheck.WebForm1.PageLoad(Object sender, EventArgs e) in d:\www\api-check\portlet.aspx.cs:line 60


The real problem though is that the application's web.config file needs an extra setting block dropped in just beneath system.web:

<system.net>
<settings>
<servicePointManager expect100Continue="false" />
</settings>
</system.net>


You'll have to do this with your custom portlets, but it's may also necessary with portlets that come from Oracle/BEA. I've encountered it with the SharePoint Console, for example.

Enjoy (no hugs though),

Bill

Find recent content on the main index or look in the archives to find all content.