Wednesday, August 28, 2013

ADF Mobile Setup(Android and IOS)

Build Mobile Apps In ADF Mobile

Speed up ADF Mobile Deployment to Android with Keystore and "Release" Packaging

As you might have noticed from my latest ADF Mobile entries, I'm doing most of my ADF Mobile development on a windows machine and testing on an Android device. Unfortunately the Android/windows experience is not as fast as the iOS/Mac one.
However, there is one thing I learned today that can make this a bit less painful in terms of the speed to deploy and test your application - and this is to use the "Release" mode when deploying your application instead of the "Debug" mode.
To do this you'll first need to define a keystore, but as Joe from our Mobile team showed me today, this is quite easy.
Here are the steps:
Open a command line in your JDK bin directory (I just used the JDK that comes with the JDeveloper install).
Issue the following command:
keytool –genkey –v –keystore <Keystore Name>.keystore –alias <Alias Name> -keyalg RSA –keysize 2048 –validity 10000
Both keystore name and alias names are strings that you decide on.
The keytool utility will then prompt you with various questions that you'll need to answer.

Once this is done, the next step is to configure your JDeveloper preferences->ADF Mobile to add this keystore there under the release tab:

 Then for your application specific deployment profile - switch the build mode from debug to release.

The end result is a much smaller mobile application (for example from 60 to 21mb) and a much faster deployment cycle (for me it is about twice as fast as before).


For even faster deployment on Android - deploy to a device instead of the emulator.
As for size of the apk file there is a minimum size of 9mb that is needed for the JVM. Frankly I don't think this is an issue for people on the store - angry birds is bigger than this and they didn't have any problems getting millions of users to download their application.

Failed to fetch URL https://dl-ssl.google.com/android/repository/repository-7.xml, reason: SSLPeerUnverified peer not authenticated

Try using "http" instead of "https". Go to the Android SDK Manager -> Tools -> Options... and check "Force https://... sources to be fetched using http://...".
enter image description here 

try to clearing or unchecking the Manifest Cache in the options menu.

ADF Mobile: SQLite in ADF Mobile

If you want to save data locally (in ADF Mobile), SQLite is the way to go. SQLite is a lightweight, portable and ACID-compliant relational database management system.
There are 2 ways of getting it (the database) in your application, by using a .sql script or by creating the .db itself and adding it to your application. I will show you the .sql way.

One of the most important things to remember is that at any given time, a single instance of the SQLite database may have either a single read-write connection or multiple read-only connections.
Although SQLite complies with the SQL92 standard, there are some restrictions but I refer you to the link below for more info about that and other subjects.

Read more about SQLite in ADF Mobile here : http://docs.oracle.com/cd/E35521_01/doc.111230/e24475/amxdatabase.htm#CIAEIGEJ 

Practical part

Use case

I will show you a couple of things in this post.
  • Create a .db by using a .sql script (when your application starts).
  • How to manage the connection of your SQLite DB.
  • Security regarding the .db
  • Doing operations on your DB (SELECT, INSERT, DELETE and UPDATE)

Let's start! 

1) Before we start, we will need an .sql script. Once you obtained/created one, place it in the following folder: 
yourApplicationName/.adf/META-INF/your_script_here
In your JDev, you will see it in the Application Resources > Descriptors > ADF META-INF (you may need to refresh) (this is an example: click).

2) When you create an 'ADF Mobile Application' in your JDeveloper, you will find the LifeCycleListenerImpl.java in your ApplicationController project (it is generated by default). We will use this class to create the DB (if needed) by reading the .sql script we provided. Note that the database name = the script name! 
Also don't forget to register this class to your application (because somehow this isn't done by default). This can be done by opening adfmf-application.xml (Situated in Application Resources > Descriptors >ADF META INF > here) and add the class in 'Lifecycle Even Listener' like in the picture below:

 Add this to the start() method. It checks if the database already exist, if not it will call a method which will create it.
 

     String databaseName = "F1_DB";  
     File dbFile = new File(AdfmfJavaUtilities.getDirectoryPathRoot(AdfmfJavaUtilities.ApplicationDirectory)+"/"+databaseName+".db");  
     if(!dbFile.exists())  
     {  
        try {  
          this.initializeDatabase(databaseName);  
        } catch (Exception e) {  
          System.out.println(e.getMessage());  
        }  
      }  

 The method below is a custom method. It reads the .sql script and executes it.

 private static void initializeDatabase(String databaseName) throws Exception  
   {  
     List stmts = null;  
     try {  
       ClassLoader cl = Thread.currentThread().getContextClassLoader();  
       InputStream is = cl.getResourceAsStream(".adf/META-INF/"+databaseName+".sql");  
       if (is == null) {  
         // .sql script not found  
       }  
       BufferedReader bReader = new BufferedReader(new InputStreamReader(is));  
       stmts = new ArrayList();  
       String strstmt = "";  
       String ln = bReader.readLine();  
       while (ln != null) {  
         if (ln.startsWith("REM") || ln.startsWith("COMMIT")) {  
           ln = bReader.readLine();  
           continue;  
         }  
         strstmt = strstmt + ln;  
         if (strstmt.endsWith(";")) {  
           System.out.println(strstmt);  
           stmts.add(strstmt);  
           strstmt = "";  
           ln = bReader.readLine();  
           continue;  
         }  
         ln = bReader.readLine();  
       }  
       String Dir = AdfmfJavaUtilities.getDirectoryPathRoot(AdfmfJavaUtilities.ApplicationDirectory);  
       String connStr = "jdbc:sqlite:" + Dir + "/"+databaseName+".db";  
       Connection conn = null;  
       conn = new SQLite.JDBCDataSource(connStr).getConnection();  
       conn.setAutoCommit(false);  
       for (int i = 0; i < stmts.size(); i++)  
       {  
         Statement pStmt = conn.createStatement();  
         pStmt.executeUpdate((String)stmts.get(i));  
       }  
       conn.commit();  
       conn.close();  
     } catch (Exception ex)  
      {  
       ex.printStackTrace();  
      }  
     }  


3) Now that our database is/will be created, we need to handle the connection. You can find the source code below. It provides a method to retrieve the Connection and a method to close the connection. 


 public class DBConnectionFactory {  
   public DBConnectionFactory() {  
     super();  
   }  
   protected static Connection conn = null;  
   protected static String DBname = "F1_DB";  
   public static Connection getConnection() throws Exception  
   {  
     if (conn == null) {  
       try {  
         String Dir = AdfmfJavaUtilities.getDirectoryPathRoot(AdfmfJavaUtilities.ApplicationDirectory);  
         String connStr = "jdbc:sqlite:" + Dir + "/"+DBname+".db";  
         conn = new SQLite.JDBCDataSource(connStr).getConnection();  
       } catch (SQLException e) {  
         System.err.println(e.getMessage());  
       }  
     }  
     return conn;  
   }  
   public static void closeConnection()  
   {  
     if(conn !=null)  
     {  
       try {  
         conn.close();  
       } catch (SQLException e) {  
         System.err.println(e.getMessage()); }  
     }  
     conn = null;  
   }  
 }  

4) Now we want to do operations on our database. I would suggest to create a database controller class, which controls all operations on your local database. The code below is just an example which isn't hard to understand.

 package be.cookie.viewcontroller.controller; 
 public class DBController {  
   private static DBController db;  
   public DBController() {  
     super();  
   }  
   public static DBController getInstance()  
   {  
     if(db == null)  
       db = new DBController();  
     return db;  
   }  
   public List getDrivers()  
   {     
     List items = new ArrayList();  
     ResultSet result = this.queryLocalDB("SELECT * FROM DRIVER");  
     try {  
         while (result.next())  
         {          
           String first = result.getString("firstname");  
           String last = result.getString("lastname");  
           String img = result.getString("imgURI");  
           String nat = result.getString("nat");  
           String team = result.getString("team");  
           int wc = result.getInt("wc");  
           int gp = result.getInt("gp");  
           int gpwon = result.getInt("gpwon");  
           items.add(new Driver(first,last,img,nat,team,wc,gp,gpwon));  
         }  
     }   
     catch (SQLException e)   
     {  
        e.printStackTrace();  
     }    
     return items;  
   }  
     public List getCalendarItems()  
     {     
       List items = new ArrayList();  
       ResultSet result = this.queryLocalDB("SELECT * FROM CALENDAR");  
       try {  
           while (result.next())  
           {          
             int code = result.getInt("nbr");  
             String place = result.getString("place");  
             String date = result.getString("date");  
             String flagURI = result.getString("flagURI");  
             items.add(new CalendarItem(code,place,date,flagURI));  
           }  
       }   
       catch (SQLException e)   
       {  
          e.printStackTrace();  
       }    
       return items;  
     }  
   public String insertDrivers(List list)  
   {    
     for(int i = 0; i < list.size(); i++)  
     {  
       Driver x = (Driver)list.get(i);  
       PreparedStatement pStmt;  
       try   
       {  
         pStmt = DBConnectionFactory.getConnection().prepareStatement("INSERT INTO DRIVER VALUES(?,?,?,?,?,?,?,?,?);");  
         pStmt.setString(1, x.getFirstname());  
         pStmt.setString(2, x.getLastname());  
         pStmt.setString(3, x.getImgURI());  
         pStmt.setString(4, x.getNat());  
         pStmt.setString(5, x.getTeam());  
         pStmt.setString(6, x.getDriverURI());  
         pStmt.setInt(7, x.getWc());  
         pStmt.setInt(8, x.getGp());  
         pStmt.setInt(9, x.getGpwon());  
         pStmt.executeUpdate();  
         if(pStmt != null)  
           pStmt.close();  
       }   
       catch (Exception e)   
       {  
         return e.getMessage();  
       }  
     }  
     try   
     {  
       DBConnectionFactory.getConnection().commit();  
     }   
     catch (Exception e)   
     {  
       return e.getMessage();  
     }  
     return "";  
   }  
   public String deleteDriver(String firstname)  
   {  
       PreparedStatement pStmt;  
       try   
       {  
         pStmt = DBConnectionFactory.getConnection().prepareStatement("DELETE FROM DRIVER WHERE firstname = ? ;");  
         pStmt.setString(1, firstname);  
         pStmt.executeUpdate();  
         if(pStmt != null)  
           pStmt.close();  
       }   
       catch (Exception e)   
       {  
         return e.getMessage();  
       }  
     return "";  
   }  
   public String updateDriver(String firstname, Driver x)  
   {  
     PreparedStatement pStmt;  
     try   
     {  
       pStmt = DBConnectionFactory.getConnection().prepareStatement("UPDATE DRIVER SET team = ?, wc = ?, gp = ?, gpwon = ? WHERE firstname = ? ;");  
       pStmt.setString(1, x.getTeam());  
       pStmt.setInt(2, x.getWc());  
       pStmt.setInt(3, x.getGp());  
       pStmt.setInt(4, x.getGpwon());  
       pStmt.setString(5, firstname);  
     }   
     catch (Exception e)   
     {  
       return e.getMessage();  
     }  
     return "";  
   }  
   /**   
    * @param query  
    * @return ResultSet queryResult  
    */  
   private ResultSet queryLocalDB(String qry)  
   {  
     Statement stat = null;  
     ResultSet result = null;  
     try  
     {  
     stat = DBConnectionFactory.getConnection().createStatement();  
     result = stat.executeQuery(qry);  
       if(result.equals(null))  
       {  
         return null;  
       }  
       else  
         return result;  
     }  
     catch(Exception ex)  
     {   
       return null;  
     }   
   }  
 }  


Security

When running the code provided in this blog, people can just locate the .db file and read it by using some program (I use SQLite database browser for Mac). Ideal for debugging but not for production. Securing the .db file can be done in few lines of code! 

Use this to secure your db (you should do this in the LifeCycleListenerImpl)
      AdfmfJavaUtilities.encryptDatabase(conn, "mypassword");  

And this for using the connection (this should be changed in the DBConnectionFactory)
 OLD: conn = new SQLite.JDBCDataSource(connStr).getConnection();  
 NEW: conn = new SQLite.JDBCDataSource(connStr)).getConnection(null,"mypassword");  



But keep in the mind the following! (quotes from the dev guide)

In the preceding example, the first parameter of the getConnection method is the user name, but since SQLite does not support user-based security, this value is ignored.
Note: SQLite does not display any error messages if you open an encrypted database with an incorrect password. Likewise, you are not alerted if you mistakenly open an unencrypted database with a password. Instead, when you attempt to read or modify the data, an SQLException is thrown with the message "Error: file is encrypted or is not a database".

Caution: If you open a database incorrectly (for example, use an invalid password to open an encrypted database), and then encrypt it again, neither the old correct password, the invalid password, nor the new password can unlock the database resulting in the irretrievable loss of data.













Tuesday, August 27, 2013

Book Mark Share


function Twitter_Share() {

Monday, August 26, 2013

ORA-01654: unable to extend index PS6_MDS.MDS_ATTRIBUTES_U2 by 1024 in tablespace PS6_MDS

You need to add more space to your datafile/tablespace, or extend the index.

SQL> alter index APPLSYS.SYS_IOT_TOP_34179 storage (maxextents unlimited);

SQL> ALTER TABLESPACE <tablespace name> ADD DATAFILE '<full path and file name>' SIZE <integer> <K|M>; 

Note: 1025288.6 - How to Diagnose and Resolve UNABLE TO EXTEND Errors
https://metalink2.oracle.com/metalink/plsql/ml2_documents.showDocument?p_database_id=NOT&p_id=1025288.6

Note: 19049.1 - OERR: ORA 1654 unable to extend index by for tablespace
https://metalink2.oracle.com/metalink/plsql/ml2_documents.showDocument?p_database_id=NOT&p_id=19049.1

Note: 762273.1 - ORA-1654: unable to extend index 
https://metalink2.oracle.com/metalink/plsql/ml2_documents.showDocument?p_database_id=NOT&p_id=762273.1

Tuesday, August 13, 2013

Unknown character set in properties bundle

Problem : I faced some issue in Jdeveloper ,when i installed JDeveloper in Linux ,my application spanish properties bundle showing unknown character set.

Solution : JDeveloper-->Tools-->Preferences --> Environment-->Encoading -->cp1252

Tuesday, August 6, 2013

WebCenter Performance Tuning Links


Understanding CLIENT_STATE_MAX_TOKENS

WebCenter Portal Pretty URL Beyond Limits

Custom PanelAccordion without using a PanelAccordion

Webcenter High Avilability

Webcenter Basic Application

Extending the Spaces Application Using JDeveloper

Webcenter Sweet

Sorting Maps

import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.WeakHashMap;

import org.apache.poi.hssf.record.formula.functions.Weekday;


public class Aaaaaaaa {

  
  
    public static void main(String args[]){
      
        WeakHashMap hashMap=new WeakHashMap();
        hashMap.put("5","Sreedhar5" );
        hashMap.put("6","Sreedhar6" );
        hashMap.put("2","Sreedhar2" );
        hashMap.put("4","Sreedhar4" );
        hashMap.put("7","Sreedhar7" );
        hashMap.put("8","Sreedhar8" );
      
        HashMap passedMap=new HashMap();
        passedMap.put("5","Sreedhar5" );
        passedMap.put("6","Sreedhar6" );
        passedMap.put("2","Sreedhar2" );
        passedMap.put("4","Sreedhar4" );
        passedMap.put("7","Sreedhar7" );
      
      
        passedMap=sortHashMapByValuesD(passedMap);
      
        System.out.println(":::passedMap::::"+passedMap);
        System.out.println("\n hashMap::::::"+hashMap);
      
        System.out.println(":::::::"+sortHashMapByValues(passedMap, false));
    }
  
    public static LinkedHashMap sortHashMapByValuesD(HashMap passedMap) {
        List mapKeys = new ArrayList(passedMap.keySet());
        List mapValues = new ArrayList(passedMap.values());
        Collections.sort(mapValues);
        Collections.sort(mapKeys);
          
        LinkedHashMap sortedMap =
            new LinkedHashMap();
      
        Iterator valueIt = mapValues.iterator();
        while (valueIt.hasNext()) {
            Object val = valueIt.next();
            Iterator keyIt = mapKeys.iterator();
          
            while (keyIt.hasNext()) {
                Object key = keyIt.next();
                String comp1 = passedMap.get(key).toString();
                String comp2 = val.toString();
              
                if (comp1.equals(comp2)){
                    passedMap.remove(key);
                    mapKeys.remove(key);
                    sortedMap.put((String)key, (String)val);
                    break;
                }

            }

        }
        return sortedMap;
    }
  
  
    public static LinkedHashMap sortHashMapByValues(HashMap passedMap, boolean ascending) {

        //Asending and Desending
          List mapKeys = new ArrayList(passedMap.keySet());
        List mapValues = new ArrayList(passedMap.values());
        Collections.sort(mapValues);
        Collections.sort(mapKeys);

        if (!ascending)
        Collections.reverse(mapValues);

        LinkedHashMap someMap = new LinkedHashMap();
        Iterator valueIt = mapValues.iterator();
        while (valueIt.hasNext()) {
        Object val = valueIt.next();
        Iterator keyIt = mapKeys.iterator();
        while (keyIt.hasNext()) {
        Object key = keyIt.next();
        if (passedMap.get(key).toString().equals(val.toString())) {
        passedMap.remove(key);
        mapKeys.remove(key);
        someMap.put(key, val);
        break;
        }
        }
        }
        return someMap;
        }

}

decimal precision erroron Solution

to solve decimal precision erroron while doing division need to pass MathContext.DECIMAL32 in division method

Reversing Map

import java.util.Enumeration;
import java.util.ResourceBundle;
public class ResourceBundleTest {
public static void main(String[] args) {
    ResourceBundle rb = ResourceBundle.getBundle("test.bundletest.mybundle");
   Map map=new HashMap();
   Enumeration <String> keys = rb.getKeys();
   while (keys.hasMoreElements()) {
      String key = keys.nextElement();
      String value = rb.getString(key);
     // Saving values in reverse manner
      map.put(value,key);
      System.out.println(key + ": " + value);
    }
}

}

Concurrent Modification Exception Solution

When you try to add and remove items from the Collection/List then it will throw Concurrent Modification Exception ,to avoid that we need to use below code.
for (Iterator<type> iter = coll.iterator(); iter.hasNext(); )
{
 iter.next();
iter.remove();

}

How to copy file in Java

package com.sreedhar.file;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;

public class CopyFileExample
{
    public static void main(String[] args)
    {  

        InputStream inStream = null;
    OutputStream outStream = null;

        try{

            File afile =new File("Afile.txt");
            File bfile =new File("Bfile.txt");

            inStream = new FileInputStream(afile);
            outStream = new FileOutputStream(bfile);

            byte[] buffer = new byte[1024];

            int length;
            //copy the file content in bytes
            while ((length = inStream.read(buffer)) &gt; 0){

                outStream.write(buffer, 0, length);

            }

            inStream.close();
            outStream.close();

            System.out.println("File is copied successful!");

        }catch(IOException e){
            e.printStackTrace();
        }
    }

}

Cipher File Encryption

package test;

import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;

import javax.crypto.Cipher;
import javax.crypto.CipherInputStream;
import javax.crypto.CipherOutputStream;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.DESKeySpec;

public class CipherExample {

    public static void main(String[] args) {
        try {
            String key = "squirrel123"; // needs to be at least 8 characters for DES

            FileInputStream fis = new FileInputStream("original.txt");
            FileOutputStream fos = new FileOutputStream("encrypted.txt");
            encrypt(key, fis, fos);

            FileInputStream fis2 = new FileInputStream("encrypted.txt");
            FileOutputStream fos2 = new FileOutputStream("decrypted.txt");
            decrypt(key, fis2, fos2);
        } catch (Throwable e) {
            e.printStackTrace();
        }
    }

    public static void encrypt(String key, InputStream is, OutputStream os) throws Throwable {
        encryptOrDecrypt(key, Cipher.ENCRYPT_MODE, is, os);
    }

    public static void decrypt(String key, InputStream is, OutputStream os) throws Throwable {
        encryptOrDecrypt(key, Cipher.DECRYPT_MODE, is, os);
    }

    public static void encryptOrDecrypt(String key, int mode, InputStream is, OutputStream os) throws Throwable {

        DESKeySpec dks = new DESKeySpec(key.getBytes());
        SecretKeyFactory skf = SecretKeyFactory.getInstance("DES");
        SecretKey desKey = skf.generateSecret(dks);
        Cipher cipher = Cipher.getInstance("DES"); // DES/ECB/PKCS5Padding for SunJCE

        if (mode == Cipher.ENCRYPT_MODE) {
            cipher.init(Cipher.ENCRYPT_MODE, desKey);
            CipherInputStream cis = new CipherInputStream(is, cipher);
            doCopy(cis, os);
        } else if (mode == Cipher.DECRYPT_MODE) {
            cipher.init(Cipher.DECRYPT_MODE, desKey);
            CipherOutputStream cos = new CipherOutputStream(os, cipher);
            doCopy(is, cos);
        }
    }

    public static void doCopy(InputStream is, OutputStream os) throws IOException {
        byte[] bytes = new byte[64];
        int numBytes;
        while ((numBytes = is.read(bytes)) != -1) {
            os.write(bytes, 0, numBytes);
        }
        os.flush();
        os.close();
        is.close();
    }


}

java.lang.UnsupportedOperationException: Remote JDBC disabled Error

1) Go to the Weblogic Domain Directory and edit the setDomainEnv.sh file
2) Modify WLS_JDBC_REMOTE_ENABLED value false to true.
WLS_JDBC_REMOTE_ENABLED="-Dweblogic.jdbc.remoteEnabled=true"

3) Restart the WebLogic Servers

Create Sequence Through Trigger

CREATE OR REPLACE TRIGGER my_trigger
BEFORE INSERT
ON qname
FOR EACH ROW
-- Optionally restrict this trigger to fire only when really needed
WHEN (new.qname_id is null)
DECLARE  v_id qname.qname_id%TYPE;
BEGIN
-- Select a new value from the sequence into a local variable. As David
-- commented, this step is optional. You can directly select into :new.qname_id SELECT qname_id_seq.nextval INTO v_id FROM DUAL;
-- :new references the record that you are about to insert into qname. Hence,
-- you can overwrite the value of :new.qname_id (qname.qname_id) with the value
-- obtained from your sequence, before inserting :new.qname_id := v_id;END my_trigger;