Technology Blogs by Members
Explore a vibrant mix of technical expertise, industry insights, and tech buzz in member blogs covering SAP products, technology, and events. Get in the mix!
cancel
Showing results for 
Search instead for 
Did you mean: 
0 Kudos

Applies to:

SAP NetWeaver CE 7.2 (SP 03) / CE 7.1 Ehp 1 (SP 03), JDK 1.6/ JDK 1.5, XML, JAXB.

Summary:

In many custom business application we are using CAF Business objects their might be requirement of archive data of CAF Business Objects for auditing and future purposes. Here I am discussing step by step configuration of NetWeaver Scheduler and corresponding custom java coding.


Author(s):      Biplab Ray

Company:      Tata Consultancy Services

Created on:    22 January 2015

Author Bio:

Biplab Ray is working for Tata Consultancy Service as Assistant Consultant and development of SAP EP , composite applications using CAF, BPM, BRM, WebDynpro for Java. He also works in technologies like Java/J2EE and has depth understanding on eSOA, Webservice, Enterprise Service, XML.

Introduction

In custom composite application for data storing, normally we are using CAF Business Objects. But we required archiving them after certain time of period for auditing or future purposes. For this requirement I have made a custom application via which we can easily archive our CAF BO data and restore them when required to CAF BO. The data archive application will be triggered via NetWeaver Scheduler. The mechanism I have used to do the custom application as follows: a) read the desired CAF BO and generate one xml file with help of JAXB api into the Hard disk of the server and delete the content of the CAF BO b ) then using java util zip api to create one zip file and put the xml file into it and delete the xml file from the hard disk of the server c) and store the name of the CAF BO with actual path where the zip file stored into server into another CAF BO. d) When restore mechanism will triggered from the zip file read the content and data will be back to the actual CAF BO and entry will be delete from the History CAF BO.


Create Projects

For this custom application we required one CAF project. With the name: example/ce/archive

Implementation

CAF Project


To do the CAF project please follow the below instruction.


Steps
Screen Shots

Step 1: Choose File -> New - >

Project of your Netweaver Developer Studio

of CAF perspective.

Step 2: One popup window come and goes to the Development Infrastructure - > Development Component and press next button in the below.
Step 3: Then one popup will be come and choose Development Component type: Composite Application. And press next button.
Step 4: Then choose the software component type where you are going to create your development component.
Step 5: Then another new popup will be come and provide the details as per requirement.
Step 6: The press next button and then finish button. It will create a CAF project into your workspace.
Step 7: Now our project is ready.
Step 8 : Right click on the modeled package
Step 9: Now we are going to create a CAF BO with name BOToArchive.
Step 10: The go to the Permission tab of CAF BO and unchecked the Permission check Enabled option
Step 11: Then go to the structure tab of CAF BO and press the button Edit Main Structure
Step 12: The create two fields with name a)Id data type String cardinality 0 -1 b) Value data type xLongText cardinality 0 -1
Step 13: We have to create another CAF BO for storing archive path and CAF BO names. Provide the new CAF BO name : History and create two fields a)Id data type string b)Path data type xLongText
Step 14: Now we have to create one Application service with name : DataArchiveApp
Step 15: Then one popup will be come and provide the name of the application service. Then press finish button.
Step 16: Then it will generate the application service and check the Generate remote Interface option. Under general tab of application service.

Step 17: Now we have to create one custom structure for input parameter of delete_ZIP method.

  Structure Name : BODeleteStruct

Step 18: After you create the custom structure it should look like as screenshot.

  Cardinality ; 0 - n

Step 19: Now we have to create custom method to our application service. To do those go to the operations tab of our application service.

Then press the Add button one popup will be come and choose the first radio button with option Custom operation and then provide the name of operation.

  1. data_Archive
  2. restore_DAT_TO_BO
    c. delete_ZIP

Step 20: Now we are adding two CAF BO objects to our Application service via dependency tab of application service.
Step 21: Now we have to create few general java class for archive our data. Please go to the Java perspective and create name : JAXB_Data_Structure with package : com.tcs.jaxb.data.structure
Step 22: Now we have to create another java class name : JaxbUtil with lot of methods with package : com.tcs.jaxb.util

package com.tcs.jaxb.util;

import java.io.BufferedReader;

import java.io.BufferedWriter;

import java.io.ByteArrayOutputStream;

import java.io.File;

import java.io.FileInputStream;

import java.io.FileNotFoundException;

import java.io.FileOutputStream;

import java.io.FileReader;

import java.io.FileWriter;

import java.io.IOException;

import java.io.InputStream;

import java.io.StringReader;

import java.io.StringWriter;

import java.util.Calendar;

import java.util.Random;

import java.util.zip.ZipEntry;

import java.util.zip.ZipException;

import java.util.zip.ZipFile;

import java.util.zip.ZipInputStream;

import java.util.zip.ZipOutputStream;

import javax.xml.bind.JAXBContext;

import javax.xml.bind.JAXBException;

/**

* @author

*

*/

public class JaxbUtil {

    /**

      * This method create the zip file

and return the Absolute file path

      *

      * @Param stringsFileName -

      *            Pass the File Name to be ZIP

      * @return - A string object with absolute path

      */

    public static String createZIP

(String stringsFileName,String stringBOName) {

          String zipFileName = "";

          zipFileName = createDirectory() + "/" +

stringBOName+"-"+createId() + ".zip";

          try {

              File file = new File(zipFileName);

              ZipOutputStream out =

new ZipOutputStream(

                        new FileOutputStream(file));

              out.putNextEntry

(new ZipEntry(stringsFileName));

              BufferedReader bufferedReader

= new BufferedReader

(new FileReader(stringsFileName));

              String string;

              while ((string

= bufferedReader.readLine()) != null) {

                  out.write(string.getBytes());

              }

              bufferedReader.close();

              out.closeEntry();

              out.flush();

              out.close();

              zipFileName = file.getAbsolutePath();

          } catch (FileNotFoundException e) {

              // TODO Auto-generated catch block

              e.printStackTrace();

          } catch (IOException e) {

              // TODO Auto-generated catch block

              e.printStackTrace();

          }

          return zipFileName;

    }

    /**

      * This Method Create Unique ID

      *

      * @return - A String object with the ID

      */

    public static String createId() {

          return Long.toHexString

(Calendar.getInstance().getTimeInMillis()) + "-"

                  + Integer.toHexString

((new Random()).nextInt() % 65536);

    }

    /**

      * This method Read the ZIP File and

returns Content of the File in a String

      * object

      *

      * @Param stringFileName -

      *            Pass the File name to be read

      * @return - Content of the file in a String object

      */

    public static String

readZipFile(String stringFileName) {

ByteArrayOutputStream byteArrayOutputStream

= new ByteArrayOutputStream();

          try {

              ZipFile zipFile

= new ZipFile(new File(stringFileName));

              ZipInputStream zipInputStream

= new ZipInputStream(

                        new FileInputStream(stringFileName));

              ZipEntry zipEntry

= zipInputStream.getNextEntry();

              BufferedReader reader

= new BufferedReader(new FileReader(

                        stringFileName));

              byte[] bs = reader.readLine().getBytes();

              reader.close();

              zipInputStream.closeEntry();

              zipInputStream.close();

              InputStream inputStream

= zipFile.getInputStream(zipEntry);

              int len;

              while ((len = inputStream.read(bs)) > 0) {

                  byteArrayOutputStream

.write(bs, 0, len);

              }

              inputStream.close();

              byteArrayOutputStream.close();

          } catch (ZipException e) {

              // TODO Auto-generated catch block

              e.printStackTrace();

          } catch (IOException e) {

              // TODO Auto-generated catch block

              e.printStackTrace();

          }

          return byteArrayOutputStream.toString();

    }

    /**

      * This method Delete the passed file.

      *

      * @Param stringFileName -

      *            Pass the file path to be delete

      */

    public static void

deleteFile(String stringFileName) {

          File file = new File(stringFileName);

          if (file.exists() && file.isFile()) {

              file.delete();

          }

    }

    /**

      * This method create a New File

and write contents to the Newly Created

      * file

      *

      * @Param stringFileContent -

      *            Pass the content of the file to be written

      * @return - A string object with

Absolute File Directory

      */

    public static String

writeToHD(String stringFileContent) {

          String string = null;

          try {

              string = createDirectory()

+ "/" + createId() + ".xml";

              File file = new File(string);

              if (!file.exists()) {

                  file.createNewFile();

              }

              BufferedWriter bufferedWriter =

new BufferedWriter(new FileWriter(

                        file));

              bufferedWriter.write(stringFileContent);

              bufferedWriter.close();

              string = file.getAbsolutePath();

          } catch (IOException e) {

              // TODO Auto-generated catch block

          }

          return string;

    }

    /**

      * This Method converts Java Object

to XML Tree and Return to String Object

      *

      * @Param object -

      *            for Java Object Data Structure (With Data)

      * @Param class1 -

      *            for Java Class (Data Structure Class Instance)

      * @return - A String Object With XML Format

      */

    public static String

jaxbMarshalConvertJavaObjectToXMLTree(Object object,

              Class<?> class1) {

          StringWriter writerPage = new StringWriter();

          try {

              JAXBContext jaxbContextPage

= JAXBContext.newInstance(class1);

              jaxbContextPage

.createMarshaller().marshal(object, writerPage);

          } catch (JAXBException e) {

              // TODO Auto-generated catch block

              e.printStackTrace();

          }

          return writerPage.toString();

    }

    /**

      * This method converts XML Tree Object to Java Object.

      *

      * @Param stringReadPage -

      *            Pass Data Stream like a String object

      * @Param class1 -

      *            Pass The Data Structure Class Instance

      * @return - Object of Java Data Structure,

you have to Cast where you

      *        calling this method with Java Data Structure

      */

    public  static Object

jaxbUNMarshalConvertXMLTreeToJavaObject(

              String stringReadPage, Class<?> class1) {

          Object dataStructureReadPage = null;

          try {

              JAXBContext jaxbContextPage

= JAXBContext.newInstance(class1);

              dataStructureReadPage =

(Object) jaxbContextPage                        .createUnmarshaller().unmarshal(

                                  new StringReader(stringReadPage));

          } catch (JAXBException e) {

              // TODO Auto-generated catch block

              e.printStackTrace();

          }

          return dataStructureReadPage;

    }

    /**

      * This method create a Directory in the HD

in the defined directory e.g:

      * "/usr/sap/" + SystemName + "/XML_DAS/"

      *

      * @return - A String Object with details of

Absolute Path of Directory

      */

    public  static String createDirectory() {

          File file = null;

          String sysNam =

System.getProperty("SAPSYSTEMNAME");

          String stringDirPathName =

"/usr/sap/" + sysNam + "/" + "XML_DAS" + "/";

          if (stringDirPathName != null

&& !"".equals(stringDirPathName)) {

              file =

new File(stringDirPathName);

              if (!file.mkdirs()) {

                  file.mkdirs();

              }

          }

          if (null != file.getAbsolutePath()) {

              stringDirPathName =

file.getAbsolutePath();

          }

          return stringDirPathName;

    }

  }
Step 23: Now we have to add DC reference to use SAP NetWeaver Scheduler mechanism into our project to do that open the project into component properties and go to the dependency tab and press the add button one popup will be come and chose ENGFACADE[sap.com] and from this tree select tc/je/scheduler/api and press next button and select deploy time and build time options. And press the finish button.
Step 24: Now it will come as screenshot.

Step 25: Now we have to create Message driven bean for scheduler. Create a message driven bean of name : Example_Shcedule with supper class MDBJobImplementation with destination name : MyDestinations and then press next button and then press the finish button without changing any default configuatraion.

  Package : com.tcs.nw.scheduler
Step 26: Now we have to access the Application service due to that we have to use EJB annotation.

package com.tcs.nw.scheduler;

import javax.ejb.ActivationConfigProperty;

import javax.ejb.EJB;

import javax.ejb.MessageDriven;

import javax.jms.MessageListener;

import com.tcs.example.ce.archive.modeled

.appsrv.dataarchiveapp.

DataArchiveAppServiceLocal;

import com.sap.scheduler.

runtime.JobContext;

import com.sap.scheduler.

runtime.mdb.MDBJobImplementation;

/**

* Message-Driven Bean

implementation class for: Example_Shedule

*

*/

@MessageDriven(

          activationConfig =

{@ActivationConfigProperty( propertyName="messageSelector", propertyValue="JobDefinition='Example_JobBean'"),

                  @ActivationConfigProperty(

                  propertyName = "destinationType",

propertyValue = "javax.jms.Queue"

          ) },

          mappedName = "MyDestination")

public class Example_Shedule

extends MDBJobImplementation implements MessageListener {

    private static final long serialVersionUID =

4485561670312885280L;

    @EJB(name="com.tcs.example.ce.archive.modeled.

appsrv.dataarchiveapp.DataArchiveApp")

    DataArchiveAppServiceLocal

dataArchiveAppServiceLocal;

    /**

    * @see MDBJobImplementation

#MDBJobImplementation()

    */

    public Example_Shedule() {

        super();

        // TODO Auto-generated constructor stub

    }

    @Override

    public void onJob(JobContext arg0)

throws Exception {

          // TODO Auto-generated method stub

          dataArchiveAppServiceLocal.dataArchive(); 

    }

}

Step 27: Now we have to create job-defination.xml file into META-INF folder of ejb module of CAF project for searching the job from NetWeaver Administrator.
Step 28: Now we have to make few entries into ejb-j2ee-engine.xml under META-INF of ejb module of CAF project
Step 29 : Now we have to create few entries into application-j2ee-engine.xml file under META-INF folder of ear project of CAF for NetWeaver Scheduler<reference reference-type="hard"><reference-target target-type="service" provider-name ="sap.com">scheduler~runtime</reference-target></reference> and under module we should include below tag<entry-name>jar file of ejb module </entry-name> and <container-type>scheduler~container</container-type>

Step 30: Now we have to write our Application service implementation methods.

Below are the methods we are going to implement.

  1. data_Archive
  2. restore_DAT_TO_BO
    c. delete_ZIP

import java.util.ArrayList;

import java.util.Calendar;

import java.util.List;

import com.tcs.example.ce.archive.modeled.BOToArchive;

import com.tcs.example.ce.archive.modeled.History;

import com.tcs.example.ce.archive.modeled.bonode

.botoarchive.botoarchive.BOToArchiveServiceLocal;

import com.tcs.example.ce.archive.modeled

.bonode.history.history.HistoryServiceLocal;

import com.tcs.jaxb.data.structure.JAXB_Data_Structure;

import com.tcs.jaxb.util.JaxbUtil;

import com.sap.caf.rt.exception.CAFCreateException;

import com.sap.caf.rt.exception.CAFDeleteException;

import com.sap.caf.rt.exception.CAFFindException;

import com.sap.caf.rt.exception.CAFLockException;

import com.sap.caf.rt.exception.CAFUpdateException;

-------------------------------------------------------------------------------------------------------------

public void dataArchive() {

        JAXB_Data_Structure data_Structure

= new JAXB_Data_Structure();

        List<BOToArchive> list_BOToArchive_OUT

= new ArrayList<BOToArchive>();

        BOToArchiveServiceLocal archiveServiceLocal

= this.getBOToArchiveService();

        try {

            List<BOToArchive> list_BOToArchive

= archiveServiceLocal.findAll();

            if(list_BOToArchive != null

&& list_BOToArchive.size() > 0){

                for (BOToArchive toArchive : list_BOToArchive) {

                    list_BOToArchive_OUT.add(toArchive);

                    archiveServiceLocal.delete(toArchive);

                }

            }

        } catch (CAFFindException e) {

            // TODO Auto-generated catch block

            e.printStackTrace();

        } catch (CAFDeleteException e) {

            // TODO Auto-generated catch block

            e.printStackTrace();

        } catch (CAFLockException e) {

            // TODO Auto-generated catch block

            e.printStackTrace();

        }

        Calendar calendar = Calendar.getInstance();

        // Set the Data to JAXB Data Structure

        data_Structure.

setList_BOToArchive(list_BOToArchive_OUT);

        // Convert Java Object to XML Tree

        String string_JavaObjectToXMLTree = JaxbUtil.

jaxbMarshalConvertJavaObjectToXMLTree

(data_Structure, JAXB_Data_Structure.class);

        // Write Content To HD

        String string_ZIP_FILE_NAME_IN_HD = JaxbUtil.writeToHD(string_JavaObjectToXMLTree);

        //Create ZIP File

        String string_ZIP_FILE_NAME = JaxbUtil.createZIP

(string_ZIP_FILE_NAME_IN_HD, "BOToArchive-"

+String.valueOf(calendar.getTime()));

        //Delete The HD File

        JaxbUtil.deleteFile(string_ZIP_FILE_NAME_IN_HD);

        // Store Actual BO & Path Name in HIstroty BO

        HistoryServiceLocal historyServiceLocal =

this.getHistoryService();

        try {

            History history = historyServiceLocal.create();

            history.setId(("BOToArchive"+"-"+

String.valueOf(calendar.getTime())+"-"+JaxbUtil.createId()));

            history.setPath(string_ZIP_FILE_NAME);

            historyServiceLocal.update(history);

        } catch (CAFCreateException e) {

            // TODO Auto-generated catch block

            e.printStackTrace();

        } catch (CAFUpdateException e) {

            // TODO Auto-generated catch block

            e.printStackTrace();

        } catch (CAFLockException e) {

            // TODO Auto-generated catch block

            e.printStackTrace();

        }

    }

------------------------------------------------------------------------------------------------------

public void restoreDATTOBO(java.lang.String nameofTheArchiveBO,

java.lang.String merge_Indicator) {

        HistoryServiceLocal historyServiceLocal = this.getHistoryService();

        BOToArchiveServiceLocal archiveServiceLocal

= this.getBOToArchiveService();

        try {

  

            List<History> list_History = historyServiceLocal.findAll();

            if(merge_Indicator != null && !"".equals(merge_Indicator) && merge_Indicator.equalsIgnoreCase("Y")){

                this.dataArchive();

            }

            for (History history : list_History) {

                if(nameofTheArchiveBO !=null

&& !"".equals(nameofTheArchiveBO) && nameofTheArchiveBO.equalsIgnoreCase(history.getId())){

                    //Convert XML Tree to Java Object

                    String string_ZipFile = JaxbUtil.readZipFile(history.getPath());

                    JAXB_Data_Structure object_JAXB_Data_Structure = (JAXB_Data_Structure)JaxbUtil

.jaxbUNMarshalConvertXMLTreeToJavaObject(string_ZipFile, JAXB_Data_Structure.class);

                    List<BOToArchive> list_BOToArchive = object_JAXB_Data_Structure.getList_BOToArchive();

                    for (BOToArchive toArchive : list_BOToArchive) {

                        BOToArchive archive = archiveServiceLocal.create();

                        archiveServiceLocal.update(archive);

                        toArchive.setCreatedAt(archive.getCreatedAt());

                        toArchive.setCreatedBy(archive.getCreatedBy());

                        toArchive.setKey(archive.getKey());

                        toArchive.setModifiedAt(archive.getModifiedAt());

                        toArchive.setModifiedBy(archive.getModifiedBy());

                        archiveServiceLocal.update(toArchive);

                    }

                    historyServiceLocal.delete(history);

                    break;

                }

          

            }

        } catch (CAFFindException e) {

            // TODO Auto-generated catch block

            e.printStackTrace();

        } catch (CAFCreateException e) {

            // TODO Auto-generated catch block

            e.printStackTrace();

        } catch (CAFUpdateException e) {

            // TODO Auto-generated catch block

            e.printStackTrace();

        } catch (CAFLockException e) {

            // TODO Auto-generated catch block

            e.printStackTrace();

        } catch (CAFDeleteException e) {

            // TODO Auto-generated catch block

            e.printStackTrace();

        }

    }

--------------------------------------------------------------------------------------------------------

public void deleteZIP(com.tcs.example.ce.

archive.modeled.BODeleteStruct delete) {

        HistoryServiceLocal historyServiceLocal

= this.getHistoryService();

        if(delete != null){

            List<String> list_String = delete.getPaths();

            try {

                List<History> list_History = historyServiceLocal.findAll();

    if(list_String != null && list_String.size() > 0){

for (String string : list_String) {

    for (History history : list_History) {

                            if(history.getId().equalsIgnoreCase(string)){

    //Delete The File

                                JaxbUtil.deleteFile(history.getPath());

                                historyServiceLocal.delete(history);

                            }

                        }

                    }

                }

            } catch (CAFFindException e) {

                // TODO Auto-generated catch block

                e.printStackTrace();

            } catch (CAFDeleteException e) {

                // TODO Auto-generated catch block

                e.printStackTrace();

            } catch (CAFLockException e) {

                // TODO Auto-generated catch block

                e.printStackTrace();

            }

        }

    }

Step 31: Now we have to deploy our project to SAP Application server.

  1. Generate
  2. Build
    c. deploy

Step 32: After deployment we have to go CAF service browser to insert few data to our BO.

  BO : BOToArchive
Step 33: Now we have to configure our scheduler to archive our BO data in specified time. To do that we have to log on to the SAP WAS Application server. Under NWA
Step 34: Then select Example_MDB under Job Definitions Tab
Step 35: Then we have to create a new task for our job. Please go to the Tasks tab and press the button Add. Then select your Job.

Then press the Next Button and provide the data as below

Then press Next button.

Then press Next button. And provide the start time of your scheduler.

Then press Add button.

And then press finish button. It will go to the Tasks tab.

And you will see your task in the task list as below.

And press the refresh button on the above screen if your task

is started then it will go to the under Jobs tab.


Step 36: Our scheduler completed its task. Now we have to go to the CAF service browser to see whether our Data is archived or not from BO: BOToArchive, it should be blank at this time and our another CAF BO : History will contain with single entry.

Below Screen Shoot of History BO

Step 37: If we want restore our data from the archive file to CAF BO we have to execute the custom method: restore_DAT_TO_BO of our application service.

Please go the Web Service Navigator of your SAP WAS Application server.

And find your web service.

Then press Next button and select the specified method to execute.

Now we have to provide the credentials the name of BO to restore with

merge indicator Y or N. If Y then the current data of the BO will merge

with old data of the BO and entry from the History Bo will be deleted.

If N then if the BO if some data is their first archive the data and

restore the old data if no data is their then it will load the old data

and entry form the History BO will be deleted.

Please collect the BO name from the History BO the Id filed value.

Then press Next button.

Now to check whether the data will restore or not go to the

CAF service browser and double click the BOToArchive CAF BO.

Now if we go to the History BO it will be empty.


Note :

To get the SAP WAS Application server name via code you have to writhe below code.

  String sysNam = System.getProperty("SAPSYSTEMNAME");
Useful Links:

http://java.sun.com

http://help.sap.com

http://jaxb.java.net


Labels in this area