Quick-n-Dirty: Import SSJS libraries with DXL

In the last time I have developed different techniques for manipulating the design elements of XPages applications. While I am still working on a way for manipulating the localization files, I was playing a little bit with DXL imports.

Here comes a Java class to import a SSJS library with DXL to a database. It allows to create a new library directly from the browser:

By clicking the Import button the new Library will be added to your database (perhaps you have to refresh the DDE):

To use the new imported code you have to sign the library first (or the complete database), otherwise you will receive a security error (This can be done in the XPage too, just alter the code of the button).

Here is the code of the example XPage:

<?xml version="1.0" encoding="UTF-8"?>
 <xp:view xmlns:xp="http://www.ibm.com/xsp/core">

    <xp:inputTextarea id="inputTextareaSSJSCode"
       value="#{sessionScope.SSJSCode}">
    </xp:inputTextarea>

    <xp:br />

    <xp:inputText id="inputTextSSJSLib" value="#{sessionScope.SSJSLib}" />

    <xp:br />

    <xp:button value="Import" id="buttonImport">
       <xp:eventHandler event="onclick" submit="true" refreshMode="complete">
       <xp:this.action>
          <![CDATA[#{javascript:
             importPackage( ch.hasselba.xpages.util );

             var dxl = SSJSLibImporter.convertToDXL(
             sessionScope.SSJSCode, sessionScope.SSJSLib,
                database.getReplicaID()
             );

             var dxlImp = sessionAsSignerWithFullAccess.createDxlImporter();
             dxlImp.setDesignImportOption( 6 );
             dxlImp.importDxl( dxl,
                sessionAsSignerWithFullAccess.getCurrentDatabase() );
          }]]>
       </xp:this.action>
     </xp:eventHandler>
   </xp:button>

</xp:view>

And here is the Java class:

package ch.hasselba.xpages.util;

import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import com.ibm.misc.BASE64Encoder;

/**
 * Helper Class for DXL Import
 * of a SSJS library
 *
 * @author Sven Hasselbach
 * @version 0.2
 * @category DXL
 * @category Util
 */
public class SSJSLibImporter {

    /**
     * converts a integer to a byte array
     * in little endian order
     *
     * @param i integer to convert
     * @return byte array
     */
    static byte[] toBytes(final int i)
    {
            ByteBuffer b = ByteBuffer.allocate(4);
            b.order( ByteOrder.LITTLE_ENDIAN );
            b.putInt(i);
                return b.array();
    }

    /**
     * encapsulates raw SSJS lib data to RT records
     *  
     * @param data array to encapsulate
     * @return byte array with RT records
     */
    public static byte[] generateSSJSBlock( byte[] data ){

            final int RECORDLENGTH_OVERALL = 50;
            final int RECORDLENGTH_BLOB = 18;

            int size = data.length;  // size of the data
            int roundedSize = (size % 2 == 0)?size:size+1; // rounded size

            byte[] record = new byte[ roundedSize + RECORDLENGTH_OVERALL ];
            byte[] hlp;

            // Record Type (Event)
            record[0] = -7;
            record[1] = -1;

            // Record Length
            record[2] = 32;
            record[3] = 0;

            // event type
            record[8] = 22;
            record[9] = 0;

            // action type
            record[10] = 4;
            record[11] = 0;

            // data size
            hlp = toBytes( size );
            record[12] = hlp[0];
            record[13] = hlp[1];

            // Record Type (Blob)
            record[32] = -36;
            record[33] = -1;

            // Rounded size + recordlength
            hlp = toBytes( roundedSize + RECORDLENGTH_BLOB );
            record[34] = hlp[0];
            record[35] = hlp[1];

            record[36] = -7;
            record[37] = -1;

            // Rounded size
            hlp = toBytes( roundedSize );
            record[38] = hlp[0];
            record[39] = hlp[1];

            record[40] = 32;
            record[41] = 78;

            // Add data to BLOB          
            for( int  i=0; i<data.length; i++ ){
                    record[i+RECORDLENGTH_OVERALL] = data[i];
            }
            return record;
    }

    /**
     * generates the DXL to import a new SSJS library
     *
     * @param data array of bytes 
     * @param libName Name of the SSJS library
     * @param dbReplicaId
     * @return DXL to import
     * 
     */
    public static String generateSSJSDXL( byte[] data, final String libName, final String dbReplicaId ){
            StringBuffer dxl = new StringBuffer();
            BASE64Encoder benc = new BASE64Encoder();
            dxl.append( "<?xml version='1.0'?><!DOCTYPE scriptlibrary SYSTEM 'xmlschemas/domino_8_5_3.dtd'>" );
            dxl.append( "<scriptlibrary name='" + libName + "' xmlns='http://www.lotus.com/dxl' version='8.5' " );
            dxl.append( "maintenanceversion='3.0' replicaid='" + dbReplicaId + "' hide='v3 v4strict' " );
            dxl.append( "designerversion='8.5.3'>" );
            dxl.append( "<item name='$Flags'><text>.5834Q</text></item>" );
            dxl.append( "<item name='$ServerJavaScriptLibrary' sign='true'>" );
            dxl.append( "<rawitemdata type='1'>" );
            dxl.append( benc.encode( data ) );
            dxl.append( "</rawitemdata></item></scriptlibrary>" );

            return dxl.toString();

    }

    /**
     * converts a String to a DXL for a SSJS library to import
     *
     * @param String to convert
     * @param Library name
     * @param ReplicaId
     * @return String with DXL
     */
    public static String convertToDXL( String raw, String libName, String dbReplicaId ){
            byte[] data = generateSSJSBlock( raw.getBytes() );
            return generateSSJSDXL( data, libName, dbReplicaId );          
    }

}

This class only imports a new SSJS library. If you want to update an existing library, you need to add a <note-info> tag to the DXL. And don’t forget to update the ACL of your database, otherwise the DXL import will fail!

P.S. Keep in mind that this article has been posted in the “Quick-n-Dirty” category.

Dieser Beitrag wurde unter Allgemein, Java, ServerSide JavaScript, XPages abgelegt und mit , , , , , , verschlagwortet. Setze ein Lesezeichen auf den Permalink.

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert.