Monday, March 26, 2012

ADF: debugging taskflows

I was having huge hassles with my task flow rerouting to themselves. I am using routers and pageflow scope varibles across bounded task flows. Mainly failed on task flow return items that went by default to a router.


This post saved my bacon : http://biemond.blogspot.com/2008/10/debugging-task-flow-in-jdeveloper-11g.html

Before and after listeners in your task-flow-call are also helpful for debugging:
<before-listener>#{viewScope.chargeOutsEditBean.afterListener}</before-listener>
<after-listener>#{viewScope.chargeOutsEditBean.afterListener}</after-listener>


  public String beforeListener() {
    System.out.println("beforeListener() {");
    System.out.println("--------------------------->route Before:" + ADFContext.getCurrent().getPageFlowScope().get("route"));
    return "blist";
  }


  public String afterListener() {
    System.out.println("afterListener() {");
    System.out.println("--------------------------->route After:" + ADFContext.getCurrent().getPageFlowScope().get("route"));
    return "list";
  }

ADF odd error : ADFC-10001: cannot instantiate class

Running one of my adf pages with some code in the construtor O got the following error:

JspServlet error: Servlet unable to dispatch to the following requested page: The following exception occurred:javax.faces.FacesException: javax.faces.FacesException: oracle.adf.controller.ControllerException:
ADFC-10001: cannot instantiate class 'za.co.test.adf.ops.view.common.form.TestBean'

I was adding a partial target to my page in the constructor which is a no no - remove the line
AdfFacesContext.getCurrentInstance().addPartialTarget(getResultTable()); and all was well again.

Note: this can also be caused by any error in the bean constructor.

Friday, March 16, 2012

Java basic encryption decrypt util


Because I always need to do this for passwords in files and various utilities I thought I would post the code.

Note: it is more secure to encrypt one way (cryptographic hashing) this is for simple no hassle cases.



package za.co.test.common.util;



import java.io.UnsupportedEncodingException;
import java.security.InvalidKeyException;
import java.security.Key;
import java.security.NoSuchAlgorithmException;

import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.spec.SecretKeySpec;

import org.apache.commons.codec.binary.Base64;


public class EncryptionUtil {
private static final byte[] SECRET_KEY = "TESTKEY2013StormersRugby".getBytes();
    public static byte[] encryptToByteArray(String input)
        throws InvalidKeyException, BadPaddingException, IllegalBlockSizeException, NoSuchAlgorithmException, NoSuchPaddingException {
        Key key = generateKey();
        Cipher cipher = Cipher.getInstance(ALGORITHM);
        cipher.init(Cipher.ENCRYPT_MODE, key);
        byte[] inputBytes = input.getBytes();
        inputBytes = cipher.doFinal(inputBytes);
        return Base64.encodeBase64(inputBytes);
    }

    public static String decryptByteArray(byte[] encryptionBytes)
        throws InvalidKeyException, BadPaddingException, IllegalBlockSizeException, NoSuchAlgorithmException, NoSuchPaddingException {
        Key key = generateKey();
        Cipher cipher = Cipher.getInstance(ALGORITHM);
        cipher.init(Cipher.DECRYPT_MODE, key);
        byte[] recoveredBytes = Base64.decodeBase64(encryptionBytes);
        recoveredBytes = cipher.doFinal(recoveredBytes);
        String recovered = new String(recoveredBytes);
        return recovered;
    }

    public static String encrypt(String input)
        throws InvalidKeyException, BadPaddingException, IllegalBlockSizeException, NoSuchAlgorithmException, NoSuchPaddingException,
               UnsupportedEncodingException {
        byte[] inputBytes = encryptToByteArray(input);
        return new String(inputBytes);
    }

    public static String decrypt(String encryptionBytes)
        throws InvalidKeyException, BadPaddingException, IllegalBlockSizeException, NoSuchAlgorithmException, NoSuchPaddingException {
        return decryptByteArray(encryptionBytes.getBytes());
    }

    private static Key generateKey() {
        Key key = new SecretKeySpec(SECRET_KEY, ALGORITHM);
        return key;
    }

    public static void main(String[] args)
        throws Exception {
        if (args == null || args.length < 1 || args[0] == null || args[0].length() < 1) {
            throw new NullPointerException("Please enter a password. Usage : java za.co.test.common.util.EncryptionUtil ");
        }
        String password = args[0];
        String pwd = EncryptionUtil.encrypt(password);
        System.out.println("The encrypted password is ---> " + pwd);
    }
}


Wednesday, March 14, 2012

ADF: PS_TXN unique constraint violated passivation

Ok so I had this problem in a few applications and want to solve it the best way once and for all.
java.sql.SQLIntegrityConstraintViolationException: ORA-00001: unique constraint (SCHEMA.PS_TXN_PK) violated or oracle.jbo.PCollException: JBO-28030: Could not insert row into table PS_TXN, collection id . What a pain.

So I have come across a couple of methods to solve this one:

1) Cleanup table regularly - this is a poor solution and is not guaranteed to work all the time. This involves creating a job to run (maybe twice a day) to sort the sequences out and clean up tables. Although it is the easiest to implement and requires no code changes. Can use this as a stop gap measure while your developers are fixing the real problem.

2) use a file store for passivation - better solution this one but I must test the performance impact and what to do if the filestore get corrupt. This involves setting the AM property  jbo.passivationstore = file on all Application Modules. Not convinced this is the best solution but it should do for small apps.

3) using one schema with jbo.server.internal_connection - just specify your datasource name in this property to point to a utility schema and you should be good to go.

4) Catching the error and doing a clean at this point - Lot of work this one better than solution 1 but really not a productive use of time. (I havent tried this one)

I really need to finish the performance testing on our current application with the 11.1.2.1 and unit test before I make the call.

http://www.oracle.com/technetwork/developer-tools/jdev/overview/bc4j-temp-tables-087270.html

Friday, March 9, 2012

Weblogic and ADF : migrateSecurityStore the hard way

I was struggeling to use WSLT to migrate my policy store for our production cluster there where classpath problems and naming problems and I just want to make the process easier for my self.

So I wrote a little util to do the migration if nothing else this post will help me remeber the classes needed for the migration exercise.

Script and classpath (I can post my linux script if anyone wants it)
My jar file that you wont have but I will post the code: common.0.0.1.jar, ./migrator.jar
Non adf etc 3rd party jars: ./lib/commons-cli-1.2.jar;./lib/commons-io-2.0.1.jar;

SET WEBLOGIC_JAR=[your Middleware location]\wlserver_10.3\server\lib\weblogic.jar
SET OLD_CLASSPATH=%CLASSPATH%
SET CLASSPATH=%CLASSPATH%;%WEBLOGIC_JAR%;./lib/adf-controller-security.jar;./migrator.jar;./lib/adf-share-mbeans-wlst.jar;./lib/adfscripting.jar;./lib/commons-cli-1.2.jar;./lib/commons-io-2.0.1.jar;./lib/commons-logging-1.1.1.jar;./lib/common.0.0.1.jar;./lib/ldapjclnt11.jar;./lib/adf-share-base.jar;./lib/adf-share-security.jar;./lib/adf-share-ca.jar;./lib/adfm.jar;./lib/oracle.webservices.standalone.client.jar

%JAVA_HOME%\bin\java za.co.test.adf.common.migrate.MigrationUtil -z C:\Dev\Middleware\user_projects\domains\dev_domain\config\fmwconfig\system-jazn-data.xml -e C:\Dev\wb-ops.0.0.1.ear

SET CLASSPATH=%OLD_CLASSPATH%

Scripts directory
In the directory I run the java from ./scripts I copyed all the .py files needed for my migrator to work.
These can be found in [your Middleware location]\oracle_common\modules\oracle.jps_11.1.1\common\wlstscripts

Migration parameters and what the class does


The migration class will take the location of a jazn-data.xml file OR an ear containing the jazn-data.xml create a temporary migration jps file call the python migration script and write the policies to your specified system-jazn-data.xml file.


-s or --src source policy config name : defaults appPolicy
-d or --dst destination policy config name : defaults domainPolicy
-c or --script Location of all the .py scripts to run wlst
-j or --jazn jazn file to import location
-z or sysjazn system jazn file to copy to full location
-e or --ear Ear file to extract jazn file from : cant be used with jazn");


typical usage is just to use -e ear location and the -z system-jazn location parameters.
 
Java code stuff


Note : 

You can replace the custom streamuilts stuff as follows:

String fileContent = StreamUtil.drainToString(new FileReader(DEFAULT_MIGRATION_SCRIPT_LOCATION));
with

String fileContent =  new String (IOUtils.toByteArray(new FileInputStream(DEFAULT_MIGRATION_SCRIPT_LOCATION)));

package za.co.test.adf.common.migrate;

import java.io.File;
import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.IOException;

import java.text.MessageFormat;

import java.util.Enumeration;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;

import org.apache.commons.cli.CommandLine;
import org.apache.commons.cli.CommandLineParser;
import org.apache.commons.cli.Option;
import org.apache.commons.cli.Options;
import org.apache.commons.cli.ParseException;
import org.apache.commons.cli.PosixParser;
import org.apache.commons.io.IOUtils;

import org.python.util.InteractiveInterpreter;

import weblogic.management.scripting.utils.WLSTInterpreter;

import za.co.test.adf.common.util.StreamUtil;


public class MigrationUtil {
  static InteractiveInterpreter interpreter = null;
  private static final String DEFAULT_SCRIPT_LOCATION = "./scripts";
  private static final String DEFAULT_TMP_LOCATION = "./tmp";
  private static final String DEFAULT_WLST_SCRIPT_LOCATION
    = DEFAULT_SCRIPT_LOCATION + "/wlst";
  private static final String DEFAULT_MIGRATION_SCRIPT_LOCATION
    = DEFAULT_SCRIPT_LOCATION + "/migrate-jps-config.xml";
  private static final String DEFAULT_JAZN_SUFFIX = "/jazn-data.xml";
  private static final String SOURCE_OPTION_NAME = "s";
  private static final String DESTINATION_OPTION_NAME = "d";
  private static final String JAZN_OPTION_NAME = "j";
  private static final String SYSJAZN_OPTION_NAME = "z";
  private static final String EAR_OPTION_NAME = "e";
  private static final String SCRIPT_OPTION_NAME = "c";
  public MigrationUtil() {
    super();
  }

  public static void main(String[] args) throws IOException, ParseException {
    String scriptLocation = DEFAULT_WLST_SCRIPT_LOCATION;
    String source = "appPolicy";
    String destination = "domainPolicy";
    String jaznFile = null;
    String systemJaznLocation = null;
    String migrationFileEar = null;

    args = new String[] { "--sysjazn", "C:/Dev/Middleware/user_projects/domains"
      +"/dev_domain/config/fmwconfig/system-jazn-data.xml", "-e",
      "C:\\Dev\\Projects\\WesbankADF\\deploy\\wb-home.0.0.1.ear"};
    CommandLineParser parser = new PosixParser();
    Options options = createOptions();
    CommandLine cmd = parser.parse(options, args);
    if(cmd.hasOption(SOURCE_OPTION_NAME)) {
      source = cmd.getOptionValue(SOURCE_OPTION_NAME);
    }
    if(cmd.hasOption(DESTINATION_OPTION_NAME)) {
      destination = cmd.getOptionValue(DESTINATION_OPTION_NAME);
    }
    if(cmd.hasOption(SCRIPT_OPTION_NAME)) {
      scriptLocation = cmd.getOptionValue(SCRIPT_OPTION_NAME);
    }
    if(cmd.hasOption(JAZN_OPTION_NAME)) {
      jaznFile = cmd.getOptionValue(JAZN_OPTION_NAME);
    }
    if(cmd.hasOption(EAR_OPTION_NAME)) {
      migrationFileEar = cmd.getOptionValue(EAR_OPTION_NAME);
    }
    if((jaznFile == null || jaznFile.length() < 1) &&
     (migrationFileEar == null || migrationFileEar.length() < 1)) {
      throw new ParseException(
        "Either ear option name (-e) or jazn file name (-j) must be populated");
    }

    if(cmd.hasOption(SYSJAZN_OPTION_NAME)) {
      systemJaznLocation = cmd.getOptionValue(SYSJAZN_OPTION_NAME);
    }

    systemJaznLocation = systemJaznLocation.replaceAll("\\\\", "/");
    System.out.println("Performing migration....");
    migrate(scriptLocation, source, destination, jaznFile,
      migrationFileEar, systemJaznLocation);
    System.out.println(".... Done .....");
  }

  public static void migrate(String scriptLocation, String source,
   String destination, String migrationFile,
    String migrationFileEar, String systemJaznLocation) throws IOException {
    StringBuilder builder = null;
    interpreter = new WLSTInterpreter();
    builder = new StringBuilder("sys.path.append('").append(scriptLocation)
      .append("')");
    interpreter.exec(builder.toString());
    interpreter.exec("import sys");
    interpreter.exec("import imp");
    interpreter.exec("import jpsWlstCmd");
    interpreter.exec("srcApp = None");
    interpreter.exec("dstApp = None");
    interpreter.exec("srcFolder = None");
    interpreter.exec("dstFolder = None");
    interpreter.exec("dstLdifFile = None");
    interpreter.exec("srcConfigFile = None");
    interpreter.exec("processPrivRole = None");
    interpreter.exec("resourceTypeFile = None");
    interpreter.exec("overWrite = None");
    interpreter.exec("migrateIdStoreMapping = None");
    interpreter.exec("preserveAppRoleGuid = None");
    interpreter.exec("reportFile = None");
    interpreter.exec("mode = None");
    String configFile =
      getGenerateMigrationJPSFile(source, destination,
        migrationFile, migrationFileEar, systemJaznLocation);
    configFile = configFile.replaceAll("\\\\", "/");
    builder =
        new StringBuilder("jpsWlstCmd.migrateSecurityStore("
          +"type=\"policyStore\", src=\"").append(source).append("\", dst=\"")
         .append(destination)
         .append("\", srcApp=srcApp, dstApp=dstApp, srcFolder=srcFolder,"
         +" dstFolder=dstFolder, dstLdifFile=dstLdifFile, "
         +"srcConfigFile=srcConfigFile, configFile=\"")
         .append(configFile).append("\", processPrivRole=processPrivRole, resourceTypeFile=resourceTypeFile, overWrite=overWrite, migrateIdStoreMapping=migrateIdStoreMapping, preserveAppRoleGuid=preserveAppRoleGuid, reportFile=reportFile, mode=mode)");
    interpreter.exec(builder.toString());
  }

  private static String getGenerateMigrationJPSFile(String source, String destination, String fileName, String earFile,
    String systemJaznLocation) throws IOException {

    File tmpFileLocation = new File(DEFAULT_TMP_LOCATION);
    if(!tmpFileLocation.exists()) {
      tmpFileLocation.mkdirs();
    }

    String fileContent = StreamUtil.drainToString(
      new FileReader(DEFAULT_MIGRATION_SCRIPT_LOCATION));
    String jaznFile = formulateMigrationJAZNFile(
      fileName, earFile, tmpFileLocation);
    jaznFile = jaznFile.replaceAll("\\\\", "/");
    fileContent = MessageFormat.format(fileContent, 
      source, destination, systemJaznLocation, jaznFile);
    File tempFile = createTemporaryFile(fileContent,
       "migrate-jps-config", ".xml", tmpFileLocation);
    return tempFile.getCanonicalPath();
  }

  private static File createTemporaryFile(String prefix, String suffix,
    File tmpFileLocation) throws java.io.IOException,
     java.io.FileNotFoundException {
    File tempFile = File.createTempFile(prefix, suffix, tmpFileLocation);
    tempFile.deleteOnExit();
    return tempFile;
  }

  private static File createTemporaryFile(String fileContent,
    String prefix, String suffix,
    File tmpFileLocation) throws java.io.IOException, 
      java.io.FileNotFoundException {
    File tempFile = createTemporaryFile(prefix, suffix, tmpFileLocation);
    FileOutputStream fos = new FileOutputStream(tempFile);


    IOUtils.write(fileContent, fos);
    IOUtils.closeQuietly(fos);
    return tempFile;
  }

  private static String formulateMigrationJAZNFile(String fileName,
     String earFileName,
    File tmpFileLocation) throws IOException {
    if(fileName != null && fileName.trim().length() > 0) {
      return fileName;
    }

    ZipFile zipFile = new ZipFile(earFileName);
    Enumeration entries = zipFile.entries();
    while(entries.hasMoreElements()) {
      ZipEntry entry = (ZipEntry) entries.nextElement();
      if(!entry.isDirectory()) {
        if(entry.getName().endsWith(DEFAULT_JAZN_SUFFIX)) {
          File tempFile = createTemporaryFile("jazn-data-orig",
            ".xml", tmpFileLocation);
          FileOutputStream fos = new FileOutputStream(tempFile);
          IOUtils.copy(zipFile.getInputStream(entry), fos);
          IOUtils.closeQuietly(fos);
          return tempFile.getCanonicalPath();
        }
      }
    }
    return null;
  }
  private static Options createOptions() {
    Options options = new Options();
    Option source = new Option(SOURCE_OPTION_NAME, 
      "src", true, "source policy config name : defaults appPolicy");
    Option destination =
      new Option(DESTINATION_OPTION_NAME, "dst", true, 
       "destination policy config name : defaults domainPolicy");
    Option scriptLocation =
      new Option(SCRIPT_OPTION_NAME, "script", true, 
       "Loction of all the .py scripts to run wlst");
    Option migrationFile = new Option(JAZN_OPTION_NAME,
      "jazn", true, "jazn file to import location");
    Option systemJaznLocation =
      new Option(SYSJAZN_OPTION_NAME, "sysjazn", true, 
       "system jazn file to copy to full location");
    Option migrationFileEar =
      new Option(EAR_OPTION_NAME, "ear", true, 
       "Ear file to extract jazn file from : cant be used with jazn");
    source.setOptionalArg(true);
    destination.setOptionalArg(true);
    scriptLocation.setOptionalArg(true);
    systemJaznLocation.setRequired(true);
    migrationFile.setOptionalArg(true);
    migrationFileEar.setOptionalArg(true);

    options.addOption(source);
    options.addOption(destination);
    options.addOption(scriptLocation);
    options.addOption(migrationFile);
    options.addOption(systemJaznLocation);
    options.addOption(migrationFileEar);
    return options;
  }
}

Wednesday, March 7, 2012

Weblogic and ADF: Unintended Consequences new session between weblogic apps and our project structure

Ok so a bit of background the following is our project stucture and all works well between applications that are deployed on one weblogic server they share sessions and user principals and roles.

This setup allows us seperate jazn files across projects and to keep everything contained.

Our base application is common which contains a set of projects for view, model, and common java code

Common >
    LoginModule (JAAS stuff)
    Common (java code)
    Model (company wide common model components)
    View (company wide common model components)

Shared Model
    Model (All common lov, eo, vo files used across projects : NO Application Modules here)

Various applications deployed as ears like finance, reports etc that contain Model and View projects
 
Home - this is the glue that binds all our applications together in a single menu etc it has NO dependacies on the other ear applications.
  View (Menu code)

Ok so onto the problem - when logging into our home app and navigating to any other of our projects from the menu we now have to relogin not great but once the second login was done all was well with the app. I did some debugging and found on the redirect we go a new session id - weird. So I puzzeled it out when making changes for the automated login I added a property to the weblogic.xml in my view project. I removed this and everything worked as before.

The offending property:
<session-descriptor>
    <cookie-path>/home</cookie-path>
</session-descriptor>

Tuesday, March 6, 2012

ADF errors with template binding for templates within templates

I refactored my templates to contain templates within templates and all new screens I created stopped working.

By not working my binding where not found using my utils methods to get the DCBindingContainer.

For some reason when I created screens of my new templates it includes an extra form tag and binds my template to a page variable in the bindings <page path="za.co.test.pageDefs.defaultFormTemplatePageDef" id="ptb1" Refresh="ifNeeded"/>. If I remove the form tags and remove the page variable and its binding to my template all is good.

Hopefully this saves you some time.

Monday, March 5, 2012

ADF : MDS-00013: no metadata found for metadata object

Weird error happend on one of my screens when I tried to call it, all my other screens worked perfectly.

Removed the two MDS jars from my Model and View projects and like magic errors appeared in my build.

Fixed up the errors (mainly related to refactoring and windows not recognising a difference in upper/ lowercase). Also had to do a clean before I built and remove the project directory in the o.j2ee folder.


NOTE: Refactoring and changing case is dangerous.
Also had this error where I had misspelt a task flow name.