Showing posts with label coding 编程. Show all posts
Showing posts with label coding 编程. Show all posts

Thursday, April 2, 2020

Construct complex nested JSON file based on a list of JSON path

What happened was my QAs did not want to change their mind to prepare data in Excel, using 'path' concept. They're too used to that method already since the XML time. They'd like to continue the same. Row contains Path and Cell/Column contains value. Each Cell/Column represents one test case. Sounds good?

I googled and googled and tried so many solutions suggested by a lot of kind men in StackOverflow, none of the solutions really gave me what I wanted. No one really did this before that building a complex/complicated nested JSON file. I decided to write the algorithm myself. 

How does the so called complex/nested look like? It looks like below. And I had to build the JSON from this list of paths. 

$.JSONDoc.OC.AL.data_type
$.JSONDoc.OC.AL.value
$.JSONDoc.OC.SIG.data_type
$.JSONDoc.OC.SIG.value
$.JSONDoc.IN.MCPL.PRODTYPE.data_type
$.JSONDoc.IN.USER.COUNTRYCODE.data_type
$.JSONDoc.IN.USER.COUNTRYCODE.value
$.JSONDoc.IN.MCPL.LOCATION.COUNTRY.data_type
$.JSONDoc.IN.MCPL.LOCATION.COUNTRY.value
$.JSONDoc.IN.USER.FRSCR.data_type
$.JSONDoc.IN.USER.FRSCR.value
$.JSONDoc.IN.MCPL.ITEMS.value[0].QUANTITY.data_type
$.JSONDoc.IN.MCPL.ITEMS.value[0].QUANTITY.value
$.JSONDoc.IN.CLU.SPLT180.data_type
$.JSONDoc.IN.CLU.SPLT180.value
$.JSONDoc.OUT.TXN.FRC.data_type
$.JSONDoc.OUT.TXN.FRC.value[0]

The algorithm below works well so far for any JSON path that consists of JSON Array as well. I know it's not perfect but I really hope it's helpful to you guys who've bumped into the similar issue that I had. One thing to note is that the 'has' method from JSONObject does not really give accurate result if the JSONObject has multi-level of nested JSONObject. Therefore I also wrote one for myself. 

public static JSONObject createJSONObject(String[] keys, int index, String value, JSONArray jArray, JSONObject masterJObj) {
        if (index < keys.length) {
            String key = keys[index];
            String nextKey = keys[index + 1];
            if (key.contains("[")) {
                return createJSONObject(keys, index + 1, value, jArray, masterJObj);
            }
            if ((index < keys.length - 2) && nextKey.contains("[")) {
                JSONArray jsonArray = new JSONArray();
                JSONObject jobj = new JSONObject();
                Object obj2 = getObject(masterJObj, key);
                if (obj2 != null) {
                    if (obj2 instanceof JSONObject) {
                        jobj = (JSONObject) obj2;
                        if (jobj.has(nextKey)) {
                            jsonArray = jobj.getJSONArray(nextKey);
                        }
                    }
                }
                createJSONObject(keys, index + 1, value, jsonArray, masterJObj);
                jobj.put(nextKey, jsonArray);
                return jobj;
            } else {
                JSONObject jsonObject1 = null;
                if (jArray != null) {
                    if (!jArray.isEmpty()) {
                        for (int j = 0; j < jArray.length(); j++) {
                            jsonObject1 = jArray.getJSONObject(j);
                            jArray = null;
                            break;
                        }
                    } else {
                        JSONObject jsonObject2 = new JSONObject();
                        jsonObject1 = new JSONObject();
                        jsonObject1.put(key, jsonObject2);
                        jArray.put(jsonObject1);
                    }
                } else {
                    Object obj1 = getObject(masterJObj, key);
                    if (obj1 != null) {
                        jsonObject1 = (JSONObject) obj1;
                    }
                }
                if (jsonObject1 == null) {
                    jsonObject1 = new JSONObject();
                }
                if (index == keys.length - 2) {
                    JSONObject jsonObject2;
                    if (jsonObject1.has(key)) {
                        jsonObject2 = jsonObject1.getJSONObject(key);
                    } else {
                        jsonObject2 = new JSONObject();
                    }
                    if (nextKey.contains("[")) {
                        nextKey = nextKey.substring(0, nextKey.indexOf("["));
                        JSONArray jArray1 = new JSONArray();;
                        if (!jsonObject1.isEmpty() && jsonObject1.has(nextKey)) {
                            jArray1 = jsonObject1.getJSONArray(nextKey);
                        }
                        jArray1.put(value);
                        jsonObject1.put(nextKey, jArray1);
                    } else {
                        if (!jsonObject1.isEmpty()) {
                            if (jsonObject1.has(key)) {
                                JSONObject jsonObject3 = jsonObject1.getJSONObject(key);
                                jsonObject3.put(nextKey, value);
                            } else {
                                jsonObject1.put(nextKey, value);
                            }
                        } else {
                            jsonObject2.put(nextKey, value);
                            jsonObject1.put(key, jsonObject2);
                        }
                    }
                    return jsonObject1;
                } else {
                    JSONObject returnedJObj = createJSONObject(keys, index + 1, value, jArray, masterJObj);
                    if (returnedJObj != null) {
                        if (returnedJObj.has(nextKey)) {
                            jsonObject1 = returnedJObj;
                        } else {
                            if (jsonObject1.has(nextKey)) {
                                if (!returnedJObj.isEmpty()) {
                                    String nextNextKey = returnedJObj.keys().next();
                                    Object jObj3 = returnedJObj.get(nextNextKey);
                                    if (jObj3 instanceof JSONObject) {
                                        jsonObject1.getJSONObject(nextKey).put(nextNextKey, jObj3);
                                    }
                                }
                            } else {
                                jsonObject1.put(nextKey, returnedJObj);
                            }
                        }
                    }
                }
                return jsonObject1;
            }
        }
        return null;
    }
    public static Object getObject(Object object, String searchedKey) {
        if (object instanceof JSONObject) {
            JSONObject jsonObject = (JSONObject) object;
            Iterator itr = jsonObject.keys();
            while (itr.hasNext()) {
                String key = (String) itr.next();
                if (!searchedKey.equals(key)) {
                    Object obj = getObject(jsonObject.get(key), searchedKey);
                    if (obj != null) {
                        return obj;
                    }
                } else {
                    return jsonObject.get(key);
                }
            }
        } else if (object instanceof JSONArray) {
            JSONArray jsonArray = (JSONArray) object;
            return getObjectFromJSONArray(jsonArray, searchedKey);
        }

        return null;
    }

Saturday, August 10, 2019

Xpath Evaluation On XML where there are multiple Namespace Declaration and there's XMLNS Declaration Without Prefix

The XML contains multiple or more than one XMLNS namespace declaration. One of them is with declaration without prefix (http://www.ilog.com/rules/param) which causes issues where xpath can't read the Xml element.

<?xml version="1.0" encoding="UTF-8"?>
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ds="http://www.ilog.com/rules/DecisionService" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<soap:Body>
<DecisionServiceResponse >
<DecisionID>RLOS001PL62000205DRAFT_2019-07-05-13:35:57:48957</DecisionID>
<underwritingRequest xmlns="http://www.ilog.com/rules/param">
<ns0:underwritingApprovalRequest xmlns:ns0="http://www.tmbbank.com/enterprise/model">
<application xmlns="">
<projectCode/>

I have a Java class that implements javax.xml.namespace.NamespaceContext which later will be instantiated and set in the setNamespaceContext of the class javax.xml.xpath.XPath. Below showing how I override the 3 methods from the NamespaceContext interface. 
    /**
     * This method is called by XPath. It returns the default namespace, if the
     * prefix is null or "".
     *
     * @param prefix to search for
     * @return uri
     */
    public String getNamespaceURI(String prefix) {
        if (prefix == null || prefix.equals(XMLConstants.DEFAULT_NS_PREFIX)) {
            return prefix2Uri.get(DEFAULT_NS);
        } else {
            return prefix2Uri.get(prefix);
        }
    }
    //This method is not needed in this context, but can be implemented in a similar way.
    public String getPrefix(String namespaceURI) {
        return uri2Prefix.get(namespaceURI);
    }
    public Iterator<String> getPrefixes(String namespaceURI) {
        // Not implemented
        return null;
    } 
Apart from the above, there is another method as below: 
    private void putInCache(String prefix, String uri) {
            prefix2Uri.put(prefix, uri);
            uri2Prefix.put(uri, prefix);
    }
    private void storeAttribute(Attr attribute) {
        // examine the attributes in namespace xmlns
        if (attribute.getNamespaceURI() != null
                && attribute.getNamespaceURI().equals(XMLConstants.XMLNS_ATTRIBUTE_NS_URI)) {
            // Default namespace xmlns="uri goes here"
            if (attribute.getNodeName().equals(XMLConstants.XMLNS_ATTRIBUTE)) {
                putInCache(DEFAULT_NS, attribute.getNodeValue());
            } else {
                // Here are the defined prefixes stored
                putInCache(attribute.getLocalName(), attribute.getNodeValue());
            }
        }
    }
The above method would not work because are multiple xmlns declarations, and prefix2Uri is a HashMap which does not allow duplicates, hence the prefix DEFAULT will be set to the most latest xmlns="" declaration than the one highlighted in yellow as above. 

Let me print something below for your clarity: 
ns0, http://www.tmbbank.com/enterprise/model
DEFAULT, http://www.ilog.com/rules/param
DEFAULT, ""
As you can see, eventually the prefix2Uri HashMap contains only 2 entries: 
ns0, http://www.tmbbank.com/enterprise/model
DEFAULT, ""
In order to fix this, just need to add one line in the putInCache method that looks like below, highlighted in light blue: 
    private void putInCache(String prefix, String uri) {
        if (prefix2Uri.get(prefix) == null || prefix2Uri.get(prefix).equals("")) {
            prefix2Uri.put(prefix, uri);
            uri2Prefix.put(uri, prefix);
        }
    }
Besides that, the XPath query that is used to query the XML, also needs to add DEFAULT as the prefix. 

Initially, the method that builds the XPath is as below: 
    public static String getPath(Node n) {
        StringBuilder path = new StringBuilder();
        do {           
            path.insert(0, n.getNodeName());
            path.insert(0, "/");
        } while ((n = n.getParentNode()) != null && n.getNodeType() == Node.ELEMENT_NODE);
        return path.toString();
    }

Now, it should look like the below , added lines highlighted in purple:
    public static String getPath(Node n) {
        StringBuilder path = new StringBuilder();
        do {           
            if(n.getNamespaceURI() != null && !n.getNamespaceURI().equals("") && (n.getPrefix() == null || n.getPrefix().equals(""))){                path.insert(0, UniversalNamespaceCache.DEFAULT_NS + ":" + n.getNodeName());
            } else {
                path.insert(0, n.getNodeName());
            }
            path.insert(0, "/");
        } while ((n = n.getParentNode()) != null && n.getNodeType() == Node.ELEMENT_NODE);
        return path.toString();
    }




Thursday, February 8, 2018

Apache DBCP Connection Pool Issue

I'm using this Apache DBCP for Connection Pool purpose. One thing I notice is that, every time there's a network failure in between my application and the database (Sql Server), yes it will generate Socket Write Failure/Error exception, and subsequent few calls would somehow cause the  getConnection() of BasicDataSource to freeze. 

I troubleshooted this by monitoring the Processes in the Activity Monitor in Sql Server. I saw there's always a Connection created each time I fired a request. That Connection would just stay, I think my application was using this particular Connection for multiple firing of requests. If I killed this particular Connection then fire a few more times, then I managed to reproduce the issue where the getConnection() was giving no response. 

After a lot of trial and error, finally I found the resolution - maxIdle of the BasicDataSource. The default maxIdle for BasicDataSource is 8, therefore I just need to set maxIdle as zero. This time, although I fired many many times , I did not see any Connection stays in the Process of Activity Monitor anymore! No more Connection Pool freeze! 


Saturday, November 11, 2017

Apache CXF - Camel tips on WSDL Validation

I wanted to perform WSDL validation against incoming SOAP Payload.

Here's what I did:

1) In applicationContext.xml,

<cxf:cxfEndpoint id="MyEndPoint" address="http://locahost:test/" serviceClass="com.test.Test" wsdlURL="test.wsdl"  >
       
<cxf:properties>
            <entry key="schema-validation-enabled" value="true"/>
        </cxf:properties>

</cxf:cxfEndpoint>
2) In camel-context.xml, 
<camel:route id="myService">
   <camel:from uri="MyEndPoint?dataFormat=
POJO"/>
...
</camel:route>
**It is compulsory to use POJO so that it will trigger JAXB validation. Otherwise you won't see any effect. Read this RedHat's document for further study. 

Apache CXF - Camel tips on Working On HTTP Response Header

Apache Camel provides so many features. It is like a blackbox.

I wanted to change the default value of the Http Response Header, for example to set no-cache to the Cache-Control. Here's what I did:

1) Create SoapInterceptor class by extending org.apache.cxf.binding.soap.interceptor.AbstractSoapInterceptor
public class SoapInterceptor extends AbstractSoapInterceptor {
2) In the constructor, set the below line: 
        super(Phase.PRE_PROTOCOL);
        getAfter().add(SAAJInInterceptor.class.getName());
**For Phase, please read this documentation from RedHat . If you wanna become an expert in terms of this, you need to test it out one by one to master its behavior. I think it is wise to include that kind of effort to your project timeline. 

3) Implement the handleMessage(SoapMessage message) method. 
3) Inside this handleMessage, I obtain the HttpServletResponse from the below line: 
HttpServletResponse httpResponse = (HttpServletResponse) message.get(AbstractHTTPDestination.HTTP_RESPONSE);
4) Now I can set the following: 
httpResponse.setHeader("Cache-Control", "no-cache, no-store");
5) Next, in applicationContext.xml,
<cxf:cxfEndpoint id="MyEndPoint" address="http://localhost/test" serviceClass="com.test.Test" >
<cxf:inInterceptors>
            <bean id="inInterceptor1" class="com.test.interceptor.SoapInterceptor" />
        </cxf:inInterceptors>

</cxf:cxfEndpoint>

Thursday, July 30, 2015

Composite Sensor (sensor.xml) for Oracle SOA

There's a logging feature (Composite Audit Level, under 'Settings') in Oracle's Enterprise Manager Console. However, usually you will not enable it in production environment because the feature captures too much detail(even the payload!) for every transaction and hence could lead to low storage level issue if your "composite" is expected to process too many transactions every minute.

Nevertheless, we still need to capture at least one of two detail for each transaction and such detail can be very useful when coming to problem troubleshooting.

So what do we do without enabling the 'logging' feature? We use the "Composite Sensors". At code level, this composite sensor is a xml with the name "sensor.xml". At Enterprise Manager's level, an composite sensor icon will appear in each transaction line. Just click on that and it will open up a new window that shows the detail.



Thursday, April 23, 2015

Oracle SOA Composite SCAC-50012 error during Build



Earlier on my head was spinning for trying to resolve this SCAC-50012 error. JDeveloper throws out this error while building the SOA Composite. 

The compiler suggests me to go to a specific location for the scac.log file. It said the log should contain the detail for the error. 

Well yes there is error detail in the log. It says "could not initialize variable" and "the schema processor cannot find the element " blar blar. So I go ahead and check the blar blar WSDLs + XSDs. They all look perfect. So what the fuck is going on?

So I started all the "long troubleshooting process" which basically means multiple times of "Trial and Error". I removed this WSDL reference, removed that "Invoke Activity". For each change I will compile the whole thing. So I repeated this for every change. Just to narrow down where exactly has gone wrong. 

I did not perform all this in one day as I have other higher priority tasks to take care of. But on and off I will come back to this one as this problem slowly becomes a needle that keeps poking me every time the user asking for an enhancement for this particular SOA Composite. 

So today finally I managed to 'gotcha' the culprit that caused this bloody issue. It is due to the reference to a specific XSD in one of the WSDLs consumed by my SOA Composite is invalid. 

Lesson learnt. Next time the same issue comes to you, please don't "TRUST" the scac.log file. Just examine every WSDLs or XSDs in your Project. Some references may be invalid already.

Thursday, February 5, 2015

Oracle MDS File Does not Exist

Sometimes, after you import a project to your JDeveloper, if that project refers to files in MDS, and complains that the reference files are not available, but if you check in the MDS, the files are actually there.

So usually this is due the MDS that the project refers to does not have the required files. Therefore

1) you either need to put the files in the default MDS referenced by the project, OR
2) you need to make the project to refer to the correct MDS that has all the necessary files. 

For second option, this is what you need to do:

1) Edit adf-config.xml. Make sure yours looks like something like below

2) Restart your JDeveloper.

3) If things did not change, close the Application, then restart your JDev, then reimport that project.




Wednesday, January 14, 2015

Oracle's SOA Applications Adapter (SOAAppsAdapter) Update Issue




Bloody Hell. This SOAAppsAdapter thingy is so bloody tedious.

So I have SOA Composites having AqAdapter as partner to listen to Business Events.

The config for this AqAdapter however is not in EM Console, instead it is in Weblogic Console - > Deployment -> OracleAppsAdapter. Yes funny thing is It is known as "OracleAppsAdapter". So confusing.

So I changed the JDBC reference inside this OracleAppsAdapter config. Next I "update" OracleAppsAdapter. However, the pending Business Events were still not picked up by the AqAdapter.

What's wrong?

Ok. We just have to restart the SOA Composite! I do not know why, perhaps the current instances were still holding the "cache" of the AqAdapter. Something like that I guess.

If you know why, appreciate your feedback in this. Thank you.



Wednesday, January 7, 2015

Eclipse Build, M2Eclipse and Maven Build



Maven exists for quite many years already, I think close to 8 years?

But I only started dealing with Maven few months back.

I have this Maven project in my STS(Spring Tool Suite). The project is using Maven Resource Filtering and also the project also needs to generate java web service proxy classes based on a wsdl.

So what happened is somehow the Eclipse Build will not copy the file under resources folder to the target classes folder. In the end I have to specifically run Maven Build (with goals: clean compile package) to make that works.

If I only ran Maven Clean, it will not help. Instead it will screw up the project by deleting many things from the target folder and no auto geneate.

If you know the way to have Eclipse default Build to understand Maven build process. Please let me know. Thank you. 




Monday, November 10, 2014

Sudo command not found

 

Yep sometimes you'll see sudo command not found error.

The solution is quite easy and straightforward.

1) Open your Unix/Linux console, type the following command:

whereis sudo

2) It will print the current path for the sudo command. Copy that path (excluding /sudo).

3) Now, go to your HOME, for e.g. /home/<username>

4) Open up a hidden file named .profile

5) There is supposed a PATH variable in .profile. And the variable might have some values, which are some other paths there already. Now paste the path that you copied from step 1 at the tail of the other paths.

6) Open a new session of console, now you should be able to run your "sudo" command already.


Wednesday, August 20, 2014

Old school Axis 1.0 way of consuming Web Service :(



Ok. Although nowdays we have a lot of advanced web service libraries such as CFX and etc, we still have to admit that sometimes we do bump into situation that we have no choice but to use the grandpa way of consuming web service! (well at least we are lucky not to use the great-grandpa way. LOL)

Yeah somehow I have to use the Axis 1.x library to generate Web Service Java Clients or Stub for me. Well that is not a big problem but but but in my case the Web Service Provider needs SOAP Header which contains all the username token information.

That's a real headache ya!

Well, the solution is quite easy anyway. It looks like below:

import org.apache.axis.client.Stub;
import org.apache.axis.message.SOAPHeaderElement;

SOAPHeaderElement security = new SOAPHeaderElement("http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd","Security")

SOAPHeaderElement usernameToken = new SOAPHeaderElement("http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd","UsernameToken");


SOAPHeaderElement user = new SOAPHeaderElement("http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd","Username", "xxx"); 
SOAPHeaderElement password = new SOAPHeaderElement("http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd","Password", "xxxyyy");
usernameToken.addChild(user);
usernameToken.addChild(password);
security.addChild(usernameToken);
            
Execute_ptt exec = ws.getexecute_pt(new URL("http://localhost:8001/soa-infra/services/SampleWebServiceProvider"));
((Stub)exec).setHeader(security);
Next, just make your web service call using the stub.







Friday, August 8, 2014

Fixed Length File Without Delimiter and BeanIO



What happened is I have this IBM Mainframe's CobolCopyBook and I need to read a number of fields from there.

For your information the CobolCopyBook is a FixedLength file which has NO Delimiter.

My problem is that in my environment I have to stick to the BeanIO framework for the parsing. That means I cannot use the normal BufferedReader + substring way which is considered NOT SO ELEGANT way to solve this problem.

Also this is the first time I am using BeanIO. I found that the existing FixedLength utilities in BeanIO, such as the FixedLengthReader expects each line has a Carriage Return (CR or \r) or Line Feed (LF or \n). But it also allows the user to specify a "delimiter" to determine when to assume a Line.

Unfortunately in my use case, as I mentioned earlier , my file does not have any delimiter. Basically it is one string of characters. Worst still is one of the field always has the CR or LF character in it! What will happen is the BeanIO's reader will consider whatever after the CR or LF character is a brand new Line but the fact it is NOT!

To summarize, I have 2 problems here.
1) No delimiter to determine a new line
2) One of the field contains Carriage Return and Line Feed 

I was cracking head for these two problems and my colleague came out with some brilliant ideas. They suggested me to use OuterBean which contains the Target Bean as a Segment. Segment as one annotation is another BeanIO feature that does all the grouping or nested bean stuff. This approach will solve the "No Delimiter to break line" issue.

Another colleague suggested to create a custom java.io.Reader that extends from java.io.Reader and implements my own "read()" method. Because in the end BeanIO is going to invoke the "read()" method from the Reader object that is passed into its internal classes. So inside this read() method I will check if the character is either a Carriage Return or a Line Feed then I will return a space means I am actually replacing \n and \r with space. This will solve my second problem where the Carriage Return or Line Feed will cause BeanReader to take the characters after it as a new line.

So now I managed to fix these two problems with the OuterBean approach and Customized java.io.Readar approach. However this is not so complete because I don't like the replacing carriage return and line feed character with space.

public class CustomerOuterUserBean {

    @Segment(name="customerUserBeans", collection=ArrayList.class, minOccurs=0, maxOccurs=-1, type=CustomerUserBean.class )

    private List customerUserBeans = new ArrayList();

public class NpiFilterReader extends FilterReader {

    public NpiFilterReader(Reader in) {
        super(in);
    }

    @Override
    public int read() throws IOException {
        int read = super.read();
        if (read == '\r' || read == '\n')
            return ' ';

        return read;
    }


So I continued the journey and in the end I found a very very simple solution for these two issues.

What I did is to create a custom RecordParserFactory which manipulates a custom RecordReader and I overwrite the read() method for the custom RecordReadear. The read() method in the custom RecordReader  looks like follows:

public class MyFixedLengthRecordReader extends FixedLengthReader

    public String read() throws IOException, RecordIOException {

        char[] buffer = new char[300];

        if(in.read(buffer, 0, 300) != -1){

            return new String(buffer);

        }      

        return null;

    }


Note that in my use case my line is fixed at 300 characters per line.

This is the most elegant yet simple solution! Thank Divine!






Wednesday, June 25, 2014

Secure Web Services using Oracle Enterprise Manager Fusion Middleware Control

Ok. Recently I have been working on Web Service Security.

My web services are running on Oracle Enterprise Manager Fusion Middleware Control.

The security part has the following break down:

1) Authentication
Whether the service consumer is a trusted one. I am using the username-token to achieve this.

2) Authorization
In this case the service consumer is trusted. However it may not have the right to invoke the particular web service operation.

3) Transport Layer Security
TLS or SSL is generally used for transport layer protection. The idea is to encrypt every data during the transmitting process. I am yet to implement this.And I am not sure if I really need to do this in my enterprise environment. The reason is our web services are in a secure network environment. Our service consumers are all internal applications. So I am not going to cover the detail for this part in this post.

Ok. What we need to know next is all the WS-* stuff. This could take some time for you to read. And along the reading process you might get even more confusion. So I will tell you what not to be confused here, as follows:

WS-Policy VS WS-Security. WS-Policy and WS-Security are two different entities. WS-Policy is a Language, whereas WS-Security is a Conceptual Framework. 

Next we are going into the technical detail. Diagrams are not available because I am lazy to remove all the sensitive company and application name:

Scenario:
Create two users to call a particular web service and to invoke different service operations respectively.

1) You need to be aware, that for Oracle Enterprise Manager Fusion Middleware Control, the "User and Group" setup are controlled by Oracle Weblogic. The whole Oracle Enterprise Manager itself is running on Oracle Weblogic. So we are going to access two different "Portals", one is the Oracle Weblogic Administrative Console and another one is the Oracle Enterprise Manager.

2) Now our first step is to create a new user. Go to Oracle Weblogic Administrative Console -> Security Realm -> User and Group. Create your user there. Very easy. Just fill in the blanks only.

3)  I am not going to cover the "Group" because I want to keep this as simple as possible. Everything will be just "User". The "Group" is useful if you want to group different users into the same group and then instead of granting permission to multiple users you just need to grant permission to one group.

4) Now you don't need the Oracle Weblogic Administrative Console anymore. Close it kill it leave it fuck it. Our next focus is to login to the Oracle Enterprise Manager for the remaining steps.

5) I assume you have deployed your web service (to be exact, it is SOA composite exposed as a web service) using the Oracle Enterprise Manager.

6) Right click on your "domain" that hosts your SOA composite,  you will see "Web Service" appearing in the context menu. Go there and look for your particular web service and click it to go to the detail page. 

7) Go to the "policies" tab. Here you can attach any policies you like to your web service. In our case we should attach "oracle/binding_permission_authorization_policy" for Web Service Endpoint Authorization.

8) At the same tab, we must also attach a username token policy for "Authentication". Just attach any policy with the name username token. But of course you have to do this carefully. 

9) Ok. we are done with the "Attaching Policy" now. Next, go to your "domain" again. Right click on your domain and you will see "application policies" and "application roles". Using the "application roles", you can create a "role" that can consists of multiple users or groups for easier management. In our case I will just skip the "application roles" to make things simple. So we will just go straight to the "application policies".

10) At the application policies, Create an Application Grant. choose the user that you set up at step 2 as your "Grantee".

11) At the same page again, there is a section for "permission". Put something as follows:
Permission Class - oracle.wsm.security.WSFunctionPermission
Resource Name - your web service NAMESPACE/service name. Remember, it's the namespace, not endpoint address.
Permission Actions - your web service operation

Done. Now the Authorization part is completed.

12)  It is testing time now. I suggest you to create another user who is not granted any permission to the particular web service.  In fact I successfully made two different users to access to the same one web service but each of them are only authorized to invoke one particular service operation.

13) Where do you pass the username and password? In your SOAP Header. Remember to include the below part in your SOAP message.

Wednesday, April 9, 2014

My first Codenvy experience



Last year I have asked Divine to give me a chance to learn Cloud Development and recently my intention has got manifested. Thanks Divine! What happened was I was given a short assignment to quickly build one Web Application to read a CSV file and then display the data to webpage. The web application offers one function to the user, which is to allow users to select a specific date to filter the CSV data.

The thing about Codenvy is it puts everything on CLOUD! What I like most is the IDE itself is integrated with a lot of handy tools such as PAAS platforms and GitHub! 

What you need to do is just sign up! Then start coding! I picked up Spring MVC & JQuery in just one day! Imagine how this WEB IDE helped us to pick up new skill fast! Anyway of course my strong foundation in JavaScript and Java have contributed to my speed learning also. 

Here I list down my views on using Web IDE Codenvy: 

Pros
  1. The IDE is fully integrated with PAAS platforms and Github. 
  2. Code from anywhere with Internet and Browser! Your code will always be in the CLOUD! 
  3. IDE provides the appropriate directory structures and libraries with some sample code! This plus the fully integrated environment help the developer to avoid spending time in setting up the coding environment. 
Cons
  1. No auto suggestion. If you are using local IDE, you will find the auto suggestion helpful! With auto suggestion feature you don't need to go back to the API doc to find out if a certain variable or method is available to certain class. You just type dot and it will just pop out the selection list for you. Unfortunately Codenvy does not have this feature. 
  2. You cannot print to Console. Somehow System.out.print does not work for Codenvy. You will not be able to see anything in the console if you are using the System.out.print command. 
  3. No instant compilation. Instant compilation is very important to developer. I have wasted a lot of time to figure out what's wrong with my code to cause the compilation error without the help of instant compilation function. I strongly suggest Codenvy to include this feature in future because this is too important! 
  4. You cannot use Call Hierarchy. Call Hierarchy is one of my favorite way to understand a program flow easily! It is very helpful when the developer needs to troubleshoot the program.  

Monday, March 31, 2014

Now I am serious about Design Pattern



I know it is kinda late. I have been writing program following a code structure defined by some other team many years back and somehow I did not go find out what are the design patterns.

As you all know design patterns are meant to solve common programming problems in the area of program's stucture, program's behaviour and etc. I have studied all the design patterns before but without really using them, I do not rally remember them too much. The problem is whether  is if design pattern really needed in the developer's environment.

Recently I found out that actually I did use design pattern without me knowing about it. LOL. What I can identify now is the Bridge Design Pattern where in my code I created a lot of interfaces to group all the commonly used methods from different classes together. For the detail explanation of the Bridge Design Pattern you may just read about it here ---> Bridge Design Pattern

In fact, I have also used the Factory Design Pattern. This helps optimize the program's memory consumption by reducing the number of times of "instantiation". For details you may just read up Factory Design Pattern.

By the way there are something called "Architectural Pattern" aslo. This is useful for higher level end to end solution.