Nov 3, 2011

My first serious Groovy class ..... decompiling java classes with closures

After I read the chapter 6 "closures" of the book Groovy and Grails Recipe, and I decided to use the power of closures of Groovy for resource (files) with other problem that I had, decompile in one step every class of jar library.

Well, the purpose of this class is call an external java decompiler (jad) from a Groovy class and execute the command into directory where the jar file was decompressed. And by using the power of closures executes recursively into this directory until find the classes.

Well, no more words, here the class

package demo

class Executor {
// directory where the library(jar) was decompressed
def path

/**
* Execute the decompilation of the classes into the directory defined in the path
* @return
*/
def decompileClasses(){
def directory = new File(path)
//make use of closures defined in the Object class
directory.eachFileRecurse {
def name = it.absolutePath
//if the current resource hasn't a .class extension continues with next one
if (name.indexOf(".class") < 0)
return
println "Processing ..." + it
//getting the name of the class with the absolute path
name = name.substring(0, name.indexOf( ".class")) + ".java"
//defining the external command in order to be executed for every class file
def command = "D:\\Jad.exe -r -d " + path +" -sjava " + it
//execute the command
def proc = command.execute()

// Wait for the command to finish
proc.waitFor()
// Obtain status and output
println "return code: ${ proc.exitValue()}"http://www.blogger.com/img/blank.gif
println "stderr: ${proc.err.text}"
// *out* from the external program is *in* for groovy
println "stdout: ${proc.in.text}"
}
}
}

def executor = new Executor(path:"D:\\myfolder\\my_jar")
executor.decompileClasses()
http://www.blogger.com/img/blank.gif


You can find more about "executing external processes" here

The Jad decompile executable file is located in this link

So, it is really useful the use of closures in Groovy. So you can see that I didn't use an static void main like java, here the point, I have created a groovy file named Decompiler.groovy, it contains the groovy class and the groovy script, so when the groovy file is compiled the Decompiler groovy class is created, and it contains the calling to the Executor class and the decompileClasses() method.

Well, I hope to follow posting about Groovy in the future.

Jun 29, 2011

WebDynpro for Java: Tutorial of the Basic Usage of RoadMap Component

We will create a local Development component project of the type Web Dynpro as follow

Our project will contain only 3 views with the purpose of show the basic usage of the roadMap object.

After, we create our component controller RoadMap and the RoadMapView view as follow

Now, we will create the 2 views more, the previous one will contain only the RoadMap Object (RoadMapView) used in all the project, the other ones show the flow between screens.

Here the list of the 3 views: RoadMapView,  InitView, and ConfirmView.

Now, we will add the component RoadMap object (it is on the Standar Complex Group) to the RoadMapView view, but first delete the default object added to the view, after we will need to add two steps (it could be more, depends of your logic) to our roadmap object. In order to do that we will use the Outline view of the NWDS. We add the two steps as follow

The type steps to add at the RoadMap object will be ot the "RoadMapStep" type. The name of the steps are: InitStep and ConfirmStep and the properties to change in these objects are: description and name. The values "Init" and "1" to InitStep, and "Confirm" and "2" to ConfirmStep. Please, see the next picture.

 Finally, we have the RoadMapView as the next picture:

We will modify the context of the Component Controller, we are going to add two "property values" named fullName and processStep to the current context, both of them are strings. And also, we bind these properties in the others views, with the exception in the RoadMapView, we only map the processStep property value. See the next picture.

Now, we are going to add the ViewContainerUIElement object at the top on the InitView and ConfirmView views (previously delete the default object added to the view). This is important because this object will contain the RoadMapView view.

Before, we are going to modify the RoadMap Window in the diagram View, first we delete the RoadMapView, and add the InitView and set up it as default view. See the next picture.

Second, we are going to embed the RoadView view on the InitView view.

 Also, add the ConfirmView view on the Window and do the same.

Next, we define in the views the inbound and outbound plugs on the RoadMap Window object.

In the  InitView:

  • Inbound ---> fromConfirmView
  • Outboud ---> toConfirmView

In the ConfirmView

  • Inbound ---> fromInitView
  • Outboud ---> toInitView

Finally, after you link the inbound with the respective outbounf you will have the next result:


Now, we are going to add functionality and design to our views.

The RoadMapView view, we select the RoadMap object and modify the selectedStep property, we put the property value on the context named processStep. See the next picture.

 After, the InitView view could look like the follow picture.

We need to add some lines of code in the next methods: wdDoInit, onActionNext, and  onPlugfromConfirmView as follow:

  public void wdDoInit()
  {
    //@@begin wdDoInit()
    wdContext.currentContextElement().setProcessStep(STEP_INIT);
    //@@end
  }

  public void onActionNext(com.sap.tc.webdynpro.progmodel.api.IWDCustomEvent wdEvent )
  {
    //@@begin onActionNext(ServerEvent)
    wdThis.wdFirePlugToConfirmView();
    //@@end
  }

   public void onPlugfromConfirmView(com.sap.tc.webdynpro.progmodel.api.IWDCustomEvent wdEvent )
  {
    //@@begin onPlugfromConfirmView(ServerEvent)
    wdContext.currentContextElement().setProcessStep(STEP_INIT);
    //@@end
  }

And, at the end of the view controller add the next line:

  //@@begin others
    private String STEP_INIT = "InitStep";
  //@@end

Also, the method onActionNext is used on the ClickOn event on the next button on the view InitView.

Finally, the ConfirmView view could look like the follow picture.

 

 We need to add some lines of code in the next methods: wdDoInit,onActionBack , and  onPlugfromInitView as follow:

  public void wdDoInit()
  {
   
//@@begin wdDoInit()
     wdContext.currentContextElement().setProcessStep(STEP_CONFIRM);
   
//@@end
  }

  public void onActionBack (com.sap.tc.webdynpro.progmodel.api.IWDCustomEvent
wdEvent )
  {
    //@@begin onActionNext(ServerEvent)
    wdThis.wdFirePlugToInitView();
    //@@end
  }

  
public void onPlugfromInitView(com.sap.tc.webdynpro.progmodel.api.IWDCustomEvent
wdEvent )
  {
    //@@begin onPlugfromConfirmView(ServerEvent)
    wdContext.currentContextElement().setProcessStep(STEP_CONFIRM);
   
//@@end
  }

And, at the end of the view controller add the
next line:

  //@@begin others
  private String STEP_CONFIRM = "ConfirmStep";
  //@@end

Also, the method onActionBack is
used on the ClickOn event on the back button on the view ConfirmView view.

Note: The private instance variables defined at the end of the view controllers must have the same value defined on the property "id" of every RoadMapStep of the RoadMap object in the RoadMapView view.

 Finally, we need to try our web dynpro application, we need to create an application object. It will look like the final picture.

You can find the source code here.

 

 

 

Oct 30, 2009

How to .. Integration Non-SAP J2EE-based Web Applications into SAP Portal with SSO Part 2

After we have configured our portal object, we must install the gateway application and modified the target application.

1. Deployment of the Gateway Web J2EE Application:

We must to create an j2ee web application with the purpose to be a gateway from every application that want to validate the SAP Ticket Logon. I have created this application because of the problem with the sapssoext library provied from SAP, it can't be loaded from more than one classloader, then this new web application will be the unque application on the server that can load this library.

This application could expose 2 or more services, it depends of you. I will mention 2 services:

  1. /SsoGatewayWeb/ssojson.dtx : under this URI will happen the vaidation of the SAP Ticket Logon sent by the SAP Portal, it returns a JSON string with the information retrieved from the ticket.
  2. /SsoGatewayWeb/sendsso2cookietest : this URI generates HTML content, it generates the string ACL of the certificate file.

Both only accept calls from HTTP POST method

The source code of the application can download from here. This application was developed with Spring MVC 2.0.8 and Json-Lib. Also it uses servelet technology.


This project also exports a client library that should be used for projects to integrate, this is called myssoext.jar.



Note: To test the latter URI(/SsoGatewayWeb/sendsso2cookietest ), an iView must be created as we seen in the first part of this blog, the only difference is that when you edit the iView should get in the attribute "URL Template" will have to go as follow:


<System.protocol>: / / <System.server>: <System.port>
<System.uri>? <Authentication> & X509 = /my_path/on/destination_server/verify.pse


Where x509 is the name of the parameter, by example, here is a file
system path of the Unix platform. Another point to mention is that the file to test must be test into the SAP Portal that generated it, namely whether
the file "verify.pse" was created on myserverX portal, then the iView must be in myserverX SAP Portal.

2. Changing the Target Application


This integration involves changing
the destination of the application code. In our case is a Struts J2EE web
applications using Spring Framework and Strut Framework.


This will import the library "myssoext.jar". Which contains the following claes and interfaces:

com.mysap.sso.ILogonConstants
com.mysap.sso.LogonTicketException

pe.com.mydomain.ssoenablerapp.integration.ISso2TicketClient
pe.com.mydomain.ssoenablerapp.integration.IValidateMySapTicketSso
pe.com.mydomain.ssoenablerapp.integration.Sso2TicketHttpClient



Based as it is developed the target applicaton is able to identify the URL to
which you pass the SAP Logon Ticket, and this is where it performs
the authentication of the application, the uri is:

/strutsdemoweb/autentificar.do


It will be directed by URI org.apache.struts.action.ActionServlet class
of Struts Framework, and what direction, according to the
struts-config.xml file, I have modified my customized class.


I haved followed the next steps to fit my application with the gateway web application.


1. Within base web.xml file, i have added a filter, i have used it for
verification, it implements the interface pe.com.mydomain.ssoenablerapp.integration.IValidateMySapTicketSso.

The
method "isValidateMySapSsoTicket", once implemented, should be called
before any sentence in the filter class. This will validate the existence of the parameter
"MYSAPSSO2" in the received implementation of the HttpServletRequest interface.
If successful, will put two variables in session:


IlogonConstants.TICKET_SESSION: it defines that the SAP Logon Ticket, in the request, was read and achieved successfully

IlogonConstants.PORTAL_USER: attachment containing the user in the SAP
Logon Ticket, this should be the id of the user logged into the SAP
Portal and will be used for validation against the target application.


Both constants are in the package "com.mysap.sso" within the library above.


For this case must include the following libraries and their dependencies.
a. Json-lib, in its version 2.2.3 (json-lib-2.2.3-jdk13.jar) and its dependencies
1.Jakarta commons-lang 2.4
2.Jakarta commons-beanutils 1.7.0 or higher
3.Jakarta commons-collections 3.2
4.Jakarta commons-logging 1.1.1
5.Ezmorph 1.0.6

b.Jakarta Commons Http Client in version 3.1 (HTTPClient-commons-3.1.jar) and its dependencies
1.Jakarta commons-codec 1.3.
2.Jakarta commons-logging 1.1.1


2. After, we need to modify the customized struts action class. The most important
thing here is to validate the presence of 2 previous variables in the scope
"session" and executes the log-in of the user into the target application.

3. I have modified the application-context file of the spring framework to inject the HttpClient class.


<bean name = "httpClient" class =
"pe.com.mydomain.ssoenablerapp.integration.Sso2TicketHttpClient">
<property name="strUri" value="${sso2ticket.verifier.uri}"/>
<property name="strScheme" value=
"${sso2ticket.authentication.scheme}" />
<property name="strCharacterEncoding" value =
"${sso2ticket.url.character.encoding}" />
</bean>



the propertyConfigurer bean.

<bean id="propertyConfigurer" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="locations">
<list><value>classpath:configuration.properties</value></list>
</property>
</bean>

4.We need to add configuration.properties at the root of the classpath. It contains the following lines :

sso2ticket.url.character.encoding = UTF-8
sso2ticket.authentication.scheme = basicauthentication
sso2ticket.verifier.uri = /SsoGatewayWeb/ssojson.dtx

the variable sso2ticket.verifier.uri contains the URI of the gateway application that validate the SAP Logon Ticket.

the variable sso2ticket.authentication.scheme is used by the UME API.

the variable sso2ticket.url.character.encoding is used to create the cookie.

Note. The most important in the code is after you have retrieved the user from the JSON string in the target application we must authenticate with the UME API like that:

Subject objSubject = UMFactory.getLogonAuthenticator().logon(request, response, strSchemeAux);

This code line allows to bypass the default login screen.

You can download here the java code with the mentioned previous code.

I hope than you can find useful the information on this blog.

Bye, see you later.




How to .. Integration Non-SAP J2EE-based Web Applications into SAP Portal with SSO Part 1

We are going to integrate Non-SAP J2EE-based Web Applications into the SAP Portal with Application Integrator and SSO.

In this part, I will discuss the overall of these posts and configure the iView with Application Integrator


Overview of Integration.



To perform this integration must take into account the following steps:



  1. Deployment of the portal application for the creation of the system portal object
  2. Create and set the type of Application Integrator iView that will contain the applications to integrate.
  3. Installing SAPSSOEXT and SAPSECU libraries
  4. Deployment of the application gateway called SsoGatewayWeb
  5. Changing the target application.


This integration has the following restrictions:

  • It applies only for web applications based on J2EE Servlet.
  • Depend exclusively on the sucessful load of the libraries supported by SAP (sapssoext and sapsecu) in both Windows and UNIX environments.

  • The target application must have created a profile for the user id
    logged to the SAP portal, this should be equal to the id with which the logged user is
    in the portal.
  • It must have well-defined a web resource in the
    target application that allows the "login" to be used by iView of type
    "Application Integrator".
  • This solution is only applied to a SAP NetWeaver Portal 7.0.


These steps are broadly outlined below each of these steps.

Detailed Description.

1. Deployment of the application for establishment of portal partner.


We will need to deploy the application of type "Portal Application" on the portal. The name of such applications is:

com.cts.portal.appintegrator.webapp.par (link)

To install this applied to the portal will use the iView prescribed in:

"System Administration"> "Support"> Link "Portal Runtime"> "Administration Console".

To perform the action "Upload" ont "com.cts.portal.appintegrator.webapp.par" file as shown in Figure 1.

Figura 1. Admnistration console - “Portal Anywhere Admin Tools”

The purpose of this portal application is to define an object of the type "system" that will use with the Application Integrator component.

Now create the system object type in the PCD, based on the deployed file.

For this we must go to the iView "System Landscape Editor":
"System Administration"> "System Configuration"> "System Landscape.

Next, we will create a template system that use to create system objects to be
used individually by each iView of this type, as discussed below.




2.Template Creation System.



we will need to create a folder within "Portal Content" /
"My Personal Content" with the same name of the application to integrate.
Within it we'll create the folders: iView, Role and System.


a. Inside the folder "system" will create an object "system" by making use the option "System from PAR", see the Figure 2.

Figure 2. Creation of the System Template

b. Choose the option "com.cts.portal.appintegrator.webapp" associated with the portal application already deployed.

c. In Step 2, choose the unique option shown: WebApplicationIntegrator



d. In the step 3, complete the following information:

System Name: Web Application

System ID: WebApplicationIntegrator

System ID Prefix: com.cts.portal.appintegrator.webapp.



Then we click on the button "Finish" and choose to open the object
for editing, where you choose "Yes" in the attribute "Is a Template".
See Figure 3.


Figure 3. Edit Object "Template System.



Finally, we must save the changes. And we have created a template system that
will be used for any type SSO integracción using the Application
Integrator.

Next, we are going to detail the steps to integrate any web J2EE applications in the
SAP Portal using SSO. In this case we show the integration of the
application "My Struts Demo Web" which is deployed in an
application server instance (SAP
Netweaver Application Server 7.0).

Before proceeding we should have in mind:

  • Must be configured Single Sign-On between both servers.
  • The target server must accept SAP Logon Ticket.
  • The servers to integrate must be in the same domain, in this special case: mydomain.com.pe
  • Every communication must be using the POST method and possibly
    encrypted communications using SSL, HTTPS could be configured on both
    servers

3. Creation of System "MyCustomizeStrutsSSO"

Now we will create an object system from the previously created template. Shown in Figure 4.

Figure 4. Creation of system
MyCustomizeStrutsSSO

1. First, we will choose the option "Web Application", as in Figure 5.

Figure 5. Template Selection

2. In Step 2, fill the following information:

System Name: Talking to Management

System ID: MyPersonalSystem.

System ID Prefix: pe.com.mydomain.ssointegration

Then we click on the button "Finish" and open the object for editing.


3. Within the "Property Editor", choose from the attribute "Property Category" (the drop down component) the option: "Show All by Category".


4. In the group "System Definition" adds the following values.


Name of Server: myserver1.mydomain.com.pe

Port Number: 50100

Protocol of the Target system: http
URI of the web application: /strutsdemoweb/autentificar.do

Here the values that could vary, for this demonstration
applications would be the server name, port number and perhaps the
protocol of the target system.


5. In the group of attributes "UserManagment, put the following values:


Logon Method: SAPLOGONTICKET

User Mapping Type: User

See Figure 6.


Figure 6. Property Editor



6. We ensure that not be a template within the group properties "Info", and save our changes.


7. Finally, we create an alias to our system. We choose from the drop down list of
attribute "Display" under "System Aliases". And add the alias called
"myStrutsAlias.


Since the created system specifically for our target application, we will create the iView of "Application Integrator" type .

4.Creating iView “MyStrutsWebSSO”.

We need to go to the iView "Portal Content Studio" and choose the folder "iView" "we have created previously under the following path:


"Portal Content" / "My Personal Content" / "MyStrutsWebApplication"


Newxt, we'll create a new iView in the selected folder, and we follow the following steps:


1. First, we choose the type of iView to create: "Portal Component".


2. In the first step select "com.sap.portal.appintegrator.sap.


3. In the second step, selection of the portal component, choose "Generic".


4. In Step 3, General Propeiedades we enter our View details for this case as follows:

iView Name: Talking to Management

iView ID: strutssso
iView ID Prefix: pe.com.mydomain.ssointegration

Master Language: English


Finally, make click on the "Finish" button and open the iView for editing, after we choose the property to be viewed by category.


In the section "Content - Generic Launcher", configure the following attributes:

  • HTTP Request Method: POST
  • System: myStrutsAlias
  • URL Template: <System.protocol>: / / <System.server>:
    <System.port> <System.uri>? <Authentication>
  • Template URL Fragment for Single Sign-On: MYSAPSSO2 = <Request.SSO2Ticket>



Finally save the changes.


This would be all we need about portal configuration worth
mentioning that this iView must be assigned to an existing role or
create a new one and assign the role to a existing portal user to
visualize the result of the integration.


5. Installing Libraries SAPSSOEXT and SAPSECU



Having identified the operating system where our target
application is deployed, we need to download the libraries from the SAP
market place.

In the following link, these components are mentioned.

http://help.sap.com/saphelp_nw04s/helpdata/en/12/9f244183bb8639e10000000a1550b0/frameset.htm


Within the section "Dynamic Link Library SAPSSOEXT", we find the following:

"....
Download

From SAP Service Marketplace at service.sap.com / patches ®
(Downloads tab) ® SAP Support Packages ® Support Packages and Patches ®
Entry by Application Group ® Additional Components ® SAPSSOEXT ®
<platform> ® SAPSSOEXT lib for SAP logon ticket

..."

We must copy these libraries into the target server's file system. In case of Windows, should be under the system folder
called "Windows" or any directory within the% PATH% directory. In the case of
Unix or Linux, we must copy them into the folder $ LD_LIBRARY_PATH or $
LIBPATH, depending on the platform.




Please observe the following notes:

sapssoext (SAP note 1040335)

sapsecu (SAP note 870138)



6. Recovery and Installation of SAP Portal Digital Certificate


We will recover the certificate file installed on the SAP Portal through the iView "Key Store Administration, under the following path:


"System Administration"> "System Configuration"> "Keystore Administration.


Once inside the iView select "SAPLogonTicketKeypar-cert" from the
drop down list, then click the button "Download file verify.pse. As
shown in Figure 7.

Figure 7. Keystore Administration


The obtained file is copied into the file system folder of target application server. This location (URL) will be used later in the java coding.


Another important aspect is the ACL string we must have to generate,
which also will be used in coding. This value is generated by following the next sintasis template:



"the id of the issuing system" + "|" + "the client of the issuing
system" + "|" + "certification subject" + "|" + "certification issue" +
"|" + "serial number certification"


For our case will be:



PNW | 000 | OU = J2EE, CN = PNW | OU = J2EE, CN = PNW | 00

Where:

the id of the issuing system: PNW

the client of the issuing system: 000

certification subject: OU = J2EE, CN = PNW

certification issuer: OU = J2EE, CN = PNW

certification serial number: 00



Almost all this information is found in the previous picture.

In the second part of this blog, we will review to the code.

Sep 16, 2009

Show the user data of every response for the current Quick Poll in the campaign in a Flex Client, 3rd part

In this part, only we will focus in Flex client, also there are others parts, such as J2EE components, but here we don't consider here because they are out of scope of this blog. It includes to consider the following parts:

  1. Create J2EE Web Proyect, it will contain the flex client created with Flex Builder or Flash Develop IDE.
  2. Create EJB Project , it references to the java project created in the 2nd part of this blog. Here, you'll need to create a stateless session bean, and after to expose some method as Web Service. The NWDS has a wizard to do this taskes. Also, you could create a Web Services directly of the Java project by making use of the NWDS wizards.
  3. Create Flex Builder Project or FlashDevelop IDE, you create a flex client to consume the previuosly web services.
  4. Create Enterprise Project; finally we will add the web and ejb project modules, previously created, to this kind project for deployment our ear file on SAP Netweaver AS 7.0+.

Now, you will review the MXML file of our flex client (we will name FlexWebService.mxml). The main aspects of this file are the web services consumation, the treating of xml response from back end, and the datagrid flex component to show the data.

1. The web services part:




<mx:WebService id="myWebService"
wsdl="http://myserver:50200/SimpleSearchPollWS/sspollconfigws?wsdl">
<mx:operation name="getVotesPerCampaingXmlResponse"
resultFormat="object"
result="resultHandler(event)"
fault="faultHandler(event)">
</mx:operation>
</mx:WebService>



In the wsdl attribute of the mx:WebService tag, we will put the wsdl url of the previously deployed web service.Also, in the tag mx:operation we mention the name of the method to call.

Note: We could consider to make use of the mx:HTTPService component with Servletes, but I have problems with the login sesion. SAP Netweaver AS has using the JASS login (user/password) module by default, then the Flex Client doesn't save the jsession variable of the current logged user and therefore the HTTPService doesn't work. May be by making use of flashvars we could integrate the SSO session on flex client (here some link of possible useful resource ).

2. The treating of xml response from back end.


The response of the back-end need to be treat, then we write the actionscript method named


private function resultHandler(event:ResultEvent):void


This name is put on the "result" attribute of the mx:WebService attribute. Optionally, also we put on the "fault"attribute the name of the "faultHandler" function, in case of some error happen.

private function faultHandler(event:FaultEvent):void


3. The datagrid flex component to show the data.


We will create an ArrayColletion variable (it needs to be Bindable) for to be used in the datagrid component.

[Bindable]
private var myData:ArrayCollection=new ArrayCollection;

This collection will containt the DTO (data transfer object) objects. this kind of object store the information from xml response. This collection containing the dto objects willbe used as data provider of the mx:Datagrid flex component.





<mx:DataGrid id="campaignGrid"
dataProvider="{myData}"
width="100%">
<mx:columns>
<mx:DataGridColumn dataField="name"
headerText="Nombre del Usuario"
width="220"/>
<mx:DataGridColumn dataField="id"
headerText="Id de Usuario"/>
<mx:DataGridColumn dataField="email"
headerText="Email"
width="200"/>
<mx:DataGridColumn dataField="area"
headerText="Area/Departamento"
width="120"/>
<mx:DataGridColumn dataField="response"
headerText="Contesto"
width="120"/>
</mx:columns>
</mx:DataGrid>


Once compiled and released the flex client, it will be integrated on the previously web project module.

Next, a screenshot of the flex client.

Flex Client

You can download the Flex Builder project from here.

Sep 9, 2009

Show the user data of every response for the current Quick Poll in the campaign in a Flex Client, 2nd part

Only we'll review the main part of the method "getVotesPerCampaingResponse(Map map)" in the SearchService class.

Before to begin we need to consider the following items:

  • com.sapportals.wcm.control.quickpoll.extension.QPResourceManager.

  • com.sapportals.wcm.repository.IResourceContext.

  • com.sap.security.api.IUser.

In this operation we must take into account that the quick polls will be processed in according to the quick poll state: current and historical. Therefore, first we need to process the current quick poll and after to process the historical rapid quick polls of the requested campaign.

The main class is "QPResourceManager", internally it works with the com.sapportals.wcm.control.quickpoll.extension.QPBaseService class. For to get one instance of the QPResourceManager class, previously we need to get an instance of the com.sapportals.portal.security.usermanagement.IUser class, it'll reference to the portal service user "cmadmin_service" and then get reference to the ResourceContext class.


Bellow I show the java code :

IUser objNwUser = UMFactory.getServiceUserFactory().getServiceUser("cmadmin_service");
com.sapportals.portal.security.usermanagement.IUser sapUser = WPUMFactory.getUserFactory().getEP5User(objNwUser);
objResourceCtx = new ResourceContext(sapUser);
QPResourceManager objResourceManager = new QPResourceManager(objResourceCtx);

We'll put the rigth value of the repository path of the Quick Poll Service (in our case the value of "/documents/QuickPoll"):

objResourceManager.setRepositoryPath(strRepositoryPath);


Previously, the instance variable must be defined, as I show bellow:


private String strRepositoryPath = "/documents/QuickPoll";

Next, I write the code to retrieve and process the data of the current quick poll for the requested campaign.

IPropertyName objP = PropertyName.getPN(strNamespace, "quickpollvote");
ReportQuickPoll report = new ReportQuickPoll();
List lstResponses = new ArrayList();
Quickpoll objQP = objResourceManager.getCurrentQuickpoll(strCampaign);
report.setNameCampaing(strCampaign);
List lstQuickPolls = new ArrayList();
reporte.setListPolls(lstQuickPolls);
if (objQP != null)
{
QuickpollResponse objQPR = null;
String strNameResource = strRepositoryPath + "/" + strCampaign + "/" + "qp.xml";
if(!existsResource(objResourceCtx, RID.getRID(strNameResource)))
throw
new ApplicationException("Doesn't exist a current poll in the KM for the requested campaign");
LineQuickPoll lineQP = new LineQuickPoll();
lineQP.setNamePoll(objQP.getName());
lineQP.setQuestion(objQP.getQuestion());
lineQP.setStatePoll(IQuickPollConstants.STATUS_QP_OPENED_AT);
lineQP.setNameResourceKM(strNameResource);
List lstLineResponses = new ArrayList();
//
// Create an ordered list with every options of the quick poll
//
for (Iterator ite = objQP.getResponses().iterator(); ite.hasNext();) {
objQPR = (QuickpollResponse) ite.next();
lstResponses.add(objQPR.getText());
}
processLineResponses(objP, strNameResource, lineQP, lstResponses, lstQuickPolls);
}


After, into the methods processLineResponses and processProperty is the core of the service class because it retrieves the information from the quick poll engine, the user who made the vote of the current quick poll.

private void processLineResponses(IPropertyName objP, String strRIDResource, LineQuickPoll lineQP, List lstResponses, List lstQuickPolls )
throws WcmException, ResourceException{
lineQP.setNameResourceKM(strRIDResource);
RID objRID = RID.getRID(strRIDResource, null);
resource = ResourceFactory.getInstance().getResource(objRID, objResourceCtx);

//
// Getting the instance of the repository service that allow us to
// extract the information about the related resource to the
// current quick poll
//
IApplicationProperties appProps = (IApplicationProperties) ResourceFactory.getInstance().getServiceFactory().getRepositoryService(resource.getRepositoryManager(), strRepositoryService);
IAppPropertyCollection collProp = appProps.getProperties(objP, resource);
LineResponse lineResponse = null;
int totVotes = 0;
IAppProperty objX = null;
List listLineResponses = new ArrayList();
for (IAppPropertyIterator ite= collProp.iterator();ite.hasNext();){
objX = ite.next();
lineResponse = new LineResponse();
//
// Process the quick poll response and get the user information
//
processProperty(lineResponse, objX, lstResponses);
listLineResponses.add(lineResponse);
totVotes++;
}
lineQP.setListUserResponses(listLineResponses);
lineQP.setTotalVotes(Integer.valueOf(String.valueOf(totVotes)));
lstQuickPolls.add(lineQP);
}

private void processProperty(LineResponse objLine, IAppProperty objAppProperty, List lstResponses) {
//
// Getting the user who response the quick poll.
//
String strUserId = objAppProperty.getUserID();
try {
IUser objUser = UMFactory.getUserFactory().getUserByLogonID(strUserId);
objLine.setEmail(objUser.getEmail());
objLine.setUserName(objUser.getFirstName() + " " + objUser.getLastName());
objLine.setUserId(strUserId);
objLine.setArea(objUser.getDepartment());
String strValue = objAppProperty.getStringValue().replaceAll(";", "");
objLine.setResponse((String) lstResponses.get(Integer.parseInt(strValue)));
} catch (UMException e) {
makeLogException(e);
}
}

Our most important statement in the above code is the sentence:

String strUserId = objAppProperty.getUserID();

It retrieves the user of current vote. Also we must remind that we have created a list named "lstResponses", it contains the names of every QuickpollResponse object of the quick poll. This list is ordered in according to the definition in the management iview of Quick Polls.

For to convert java objects into the XML document we'll use an utility class. (you can find the source here)

String strRet = OptimizedReflectionMarshaller.marshal(getVotesPerCampaingXmlResponse(map));

In the last part, we will review the RIA Flex client to show the final web report.

Here you can download the java project.

Show the user data of every response for the current Quick Poll in the campaign in a Flex Client, 1st part

In this first part, we will learn the basic about the SAP portal KM library km.appl.ui.quickpoll_api.jar and its configuration for our development environment.

The application that we are going to create will have:

  1. input: the name of campaign to review.
  2. output: every user vote of the current quick poll with detail information of the user. As the figure 2.



Before to begin we must take in account that the following things:

  • The repository path for the quick poll is "/document/QuickPoll".
  • The name of the Quick Poll resource is qp.xml. It is for the current quick poll of the campaign. For the previous and closed quick poll they are located in the history directory of the campaign.
  • The namespace of the quick poll service is "http://sapportals.com/xmlns/cm:service.quickpoll.QPService".
  • The name of the portal service for quick poll is "AppPropertiesRepositoryService".
  • The name of the property is "quickpollvote" (link). This is the most important item because it contains all the info that we will need.


Our final RIA web report will contain information about the every response of current quick poll for the requested campaign, data as full name of the user, email, organization, and finally the vote.


We will create an xml document with the structure as the figure 1.

Figure 1.

The design of the RIA client is shown in the figure 2.

Figure 2

We will create a simple Java project, after we are going to create our pojos entities with the similar structure to the xml structure.

LineQuickPoll.java
LineResponse.java
ReportQuickPoll.java

These classes contain the following attributes with its setter and getter methods. Also they are Serializable, but it is not necessary.


-- LineQuickPoll.java --

private String namePoll;
private String question;
private String statePoll;
private String nameResourceKM;
private Integer totalVotes;
private List listUserResponses;



-- LineResponse.java --
private String userId;
private String userName;
private String email;
private String area;
private String response;



-- ReportQuickPoll.java --
private String nameCampaing;
private List listPolls;


Now, we are going to create our aplication service class, I will name it "SearchService" and it implements the ISearchService interface as I show in the following code.

public interface ISearchService {

/**
* Get the votes per user for the campaign in the current quick poll, the returned text is in an XML Format
* @param map
* @return Return an XML text
* @throws ApplicationException
*/
String getVotesPerCampaingXmlResponse(Map map) throws ApplicationException;

/**
* Get the votes per user for the campaign in the current quick poll
* @param map
* @return Return a ReportQuickPoll object
* @throws ApplicationException
*/
ReportQuickPoll getVotesPerCampaingResponse(Map map) throws ApplicationException;
}

Also I have created a J2EE Server Component Library Project with the purpose to contain all SAP KMC libraries need by the java project, it is only to compilation time, because this libraries are part of the SAP Portal in runtime.

In the next part we are going to review this service class in detail.