воскресенье, 7 октября 2012 г.

Публикация события в EDN из Java

Рассмотрим пример публикации события в EDN из Java для AQ и JMS на примере события:
 <?xml version="1.0" encoding="UTF-8" standalone="yes"?>  
 <definitions xmlns="http://schemas.oracle.com/events/edl" targetNamespace="http://schemas.oracle.com/events/edl/TestEvent">  
   <schema-import namespace="http://nl.xenta/events" location="xsd/TestEvent.xsd"/>  
   <event-definition name="EventElement">  
     <content xmlns:ns0="http://nl.xenta/events" element="ns0:TestEvent"/>  
   </event-definition>  
 </definitions>  
По-умолчанию используется механизм AQ, но можно настроить и с использованием JMS (см. 41.3.6 How to Configure JMS-based EDN Implementations)

Класс реализующий отправку события:
 import oracle.fabric.blocks.event.BusinessEventConnection;  
 import oracle.fabric.blocks.event.BusinessEventConnectionFactory;  
 import oracle.integration.platform.blocks.event.BusinessEventBuilder;  
 import oracle.integration.platform.blocks.event.jms.JmsRemoteBusinessEventConnectionFactory;  
 import oracle.integration.platform.blocks.event.saq.SAQRemoteBusinessEventConnectionFactory;  
 import oracle.soa.common.util.XMLUtil;  
 import org.w3c.dom.Element;  
 import java.util.Date;  
 import java.util.Properties;  
 import javax.jms.Queue;  
 import javax.jms.QueueConnectionFactory;  
 import javax.naming.Context;  
 import javax.naming.InitialContext;  
 import javax.naming.NamingException;  
 import javax.sql.DataSource;  
 import javax.transaction.UserTransaction;  
 import javax.xml.namespace.QName;  
   
 public class EdnUtils {  
   private static final String EDN_JMS_CONNECTION_FACTORY_NAME = "jms/fabric/EDNConnectionFactory";  
   private static final String EDN_JMS_XA_CONNECTION_FACTORY_NAME = "jms/fabric/xaEDNConnectionFactory";  
   private static final String EDN_QUEUE_NAME = "jms/fabric/EDNQueue"; 
   private static final String EDN_DATASOURCE = "jdbc/EDNDataSource";
   private static final String EDN_LOCALTX_DATASOURCE = "jdbc/EDNLocalTxDataSource"; 
   
   public static void main(String[] args) {  
     Properties props = new Properties();  
   
     props.put(Context.PROVIDER_URL, "t3://127.0.0.1:8001");  
     props.put(Context.INITIAL_CONTEXT_FACTORY, "weblogic.jndi.WLInitialContextFactory");  
     props.put(Context.SECURITY_PRINCIPAL, "weblogic");  
     props.put(Context.SECURITY_CREDENTIALS, "welcome1");  
   
     try{  
       String eventName = "EventElement";  
       String eventNamespace = "http://schemas.oracle.com/events/edl/TestEvent";  
       String eventBodyStr = "<TestEvent xmlns=\"http://nl.xenta/events\">\n"  
                   + "<action>action from java</action> \n"   
                   + "<description>description at [" + new Date() + "]</description> \n"   
                   + "</TestEvent>";  
       Element eventBody = XMLUtil.parseDocumentFromXMLString(eventBodyStr.toString()).getDocumentElement();  
        
       InitialContext context = new InitialContext(props);  
   
       EdnUtils.publishEvent(context, false, eventName, eventNamespace, eventBody);  
     } catch (Exception e) {  
       e.printStackTrace();  
     }  
   }  
   
   public static void publishEvent(InitialContext context, boolean isJmsEdnMode, String eventName,  
                   String eventNamespace, Element eventBody) throws NamingException {  
     BusinessEventConnectionFactory factory = null;  
     UserTransaction userTransaction =  
       (UserTransaction) context.lookup("javax.transaction.UserTransaction");  
   
     if (!isJmsEdnMode) {  
       DataSource ds = (DataSource) context.lookup(EDN_DATASOURCE);  
       DataSource localTxDs = (DataSource) context.lookup(EDN_LOCALTX_DATASOURCE);  
   
       factory = new SAQRemoteBusinessEventConnectionFactory(ds, localTxDs, userTransaction);  
     } else {  
       QueueConnectionFactory queueConnectionFactory =  
         ((QueueConnectionFactory) context.lookup(EDN_JMS_CONNECTION_FACTORY_NAME));  
       QueueConnectionFactory xaQueueConnectionFactory =  
         ((QueueConnectionFactory) context.lookup(EDN_JMS_XA_CONNECTION_FACTORY_NAME));  
       Queue jmsQueue = ((Queue) context.lookup(EDN_QUEUE_NAME));  
   
       factory = new JmsRemoteBusinessEventConnectionFactory(queueConnectionFactory, xaQueueConnectionFactory,  
           jmsQueue, userTransaction);  
     }  
   
     BusinessEventConnection conn = factory.createBusinessEventConnection();  
   
     BusinessEventBuilder builder = BusinessEventBuilder.newInstance();  
   
     builder.setEventName(new QName(eventNamespace, eventName));  
     builder.setBody(eventBody);  
   
     conn.publishEvent(builder.createEvent(), 3);  
     conn.close();  
   }  
 }  
Для сборки и запуска примера из JDeveloper потребуются следующие библиотеки:
Данное приложение-пример для JDeveloper содержащее два проекта (здесь):
  • EventToFile - композит который при получении события пишет в файл на файловой системе, так же через него можно отправить событие;
  • PublishEventFromJava - проект содержащий данный пример.

вторник, 25 сентября 2012 г.

Тренинги по Oracle Unified Method

Тренинги по Oracle Unified Method доступны на Oracle Learning Library.
На момент написания статьи доступно два уровня OUM: Все тренинги по OUM на Oracle Learning Library здесь.

Полезные ссылки:
  • Официальный блог здесь
  • Информация об сертификации Oracle Unified Method 5 Essentials (1Z0-568) здесь

понедельник, 17 сентября 2012 г.

Ошибка "internal xpath error" в oraext:query-database и вариант её решения

Ошибка:
При использовании XPath-функции oraext:query-database, если в запросе используются функции БД (например: select max(salary) from employee) возникает ошибка следующего вида:
 <bpelFault>  
  <faultType>0</faultType>  
  <subLanguageExecutionFault xmlns="http://docs.oasis-open.org/wsbpel/2.0/process/executable">  
   <part name="summary">  
    <summary>An error occurs while processing the XPath expression; the  
         expression is oraext:query-database("select  
         max(salary) from employee",false(),false(),'jdbc/examplesDS').</summary>  
   </part>  
   <part name="detail">  
    <detail>XPath expression failed to execute. An error occurs while  
        processing the XPath expression; the expression is  
        oraext:query-database("select max(salary) from  
        employee",false(),false(),'jdbc/examplesDS'). The XPath  
        expression failed to execute; the reason was: internal xpath  
        error. Check the detailed root cause described in the exception  
        message text and verify that the XPath query is correct.</detail>  
   </part>  
   <part name="code">  
    <code>XPath expression failed to execute</code>  
   </part>  
  </subLanguageExecutionFault>  
 </bpelFault>  
А в логе managed-сервера:
 oracle.xml.sql.OracleXMLSQLException: Character ')' is not allowed in an XML tag name.  
     at oracle.xml.sql.core.OracleXMLConvert.getXML(OracleXMLConvert.java:1178)  
     at oracle.xml.sql.query.OracleXMLQuery.getXMLDOM(OracleXMLQuery.java:417)  
     at oracle.xml.sql.query.OracleXMLQuery.getXMLDOM(OracleXMLQuery.java:384)  
     at oracle.xml.sql.query.OracleXMLQuery.getXMLDOM(OracleXMLQuery.java:345)  
     at oracle.tip.pc.services.functions.ExtFunc.queryDatabase(ExtFunc.java:152)  
     at oracle.tip.pc.services.functions.ExtFuncFunction$QueryDatabaseFunction.call(ExtFuncFunction.java:359)
     ...
Причина:
XML SQL Utility (XSU) обрабатывает имя столбца как имя тега. В нашем случае имя столбца max(salary) рассматривается XSU как недопустимое имя тега, и происходит ошибка.

Вариант решения:
Необходимо добавить алиас для столбца в котором используются функции, т.е. в нашем случае:
 oraext:query-database("select max(salary) as salary from employee",
                                       false(),false(),'jdbc/examplesDS')  

суббота, 15 сентября 2012 г.

Хеширование SHA-1 и MD5 на PL/SQL и Java

  • Реализация на PL/SQL:
    • SHA-1:
       CREATE OR REPLACE  
        FUNCTION SHA1(plain_text VARCHAR2) RETURN VARCHAR2  
        AS  
        BEGIN  
         RETURN UTL_RAW.CAST_TO_VARCHAR2(UTL_ENCODE.BASE64_ENCODE(DBMS_CRYPTO.HASH (src => utl_i18n.string_to_raw (plain_text, 'AL32UTF8'), typ => DBMS_CRYPTO.HASH_SH1)));  
        END;  
      
    • MD5:
       CREATE OR REPLACE  
        FUNCTION MD5(plain_text VARCHAR2) RETURN VARCHAR2 IS  
        BEGIN  
         RETURN RAWTOHEX(DBMS_OBFUSCATION_TOOLKIT.MD5(INPUT => TL_RAW.CAST_TO_RAW(plain_text) ));  
        END;
      
  • Реализация на Java:
    import java.math.BigInteger;
    
    import java.security.MessageDigest;
    import java.security.NoSuchAlgorithmException;
    
    public class CryptoUtils {
    
        private final static char[] ALPHABET =
            "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/".toCharArray();
    
        public static String sha1(String plain) {
            try {
                MessageDigest md = MessageDigest.getInstance("sha");
                md.update(plain.getBytes());
                byte[] digest = md.digest();
    
                return encode(digest);
                /* Альтернативные варианты:
                return javax.xml.bind.DatatypeConverter.printBase64Binary(digest);
                или
                return com.sun.org.apache.xml.internal.security.utils.Base64.encode(digest);
                */
            } catch (NoSuchAlgorithmException e) {
                e.printStackTrace();
                return null;
            }
        }
    
        public static String md5(String raw) {
            try {
                MessageDigest md = MessageDigest.getInstance("MD5");
                md.update(raw.getBytes(), 0, raw.length());
                return new BigInteger(1, md.digest()).toString(16);
            } catch (NoSuchAlgorithmException e) {
                e.printStackTrace();
                return null;
            }
        }
    
        public static String encode(byte[] buf) {
            int size = buf.length;
            char[] ar = new char[((size + 2) / 3) * 4];
            int a = 0;
            int i = 0;
            while (i < size) {
                byte b0 = buf[i++];
                byte b1 = (i < size) ? buf[i++] : 0;
                byte b2 = (i < size) ? buf[i++] : 0;
    
                int mask = 0x3F;
                ar[a++] = ALPHABET[(b0 >> 2) & mask];
                ar[a++] = ALPHABET[((b0 << 4) | ((b1 & 0xFF) >> 4)) & mask];
                ar[a++] = ALPHABET[((b1 << 2) | ((b2 & 0xFF) >> 6)) & mask];
                ar[a++] = ALPHABET[b2 & mask];
            }
            switch (size % 3) {
            case 1:
                ar[--a] = '=';
            case 2:
                ar[--a] = '=';
            }
            return new String(ar);
        }
    }
    

воскресенье, 29 июля 2012 г.

Управление структурой MDS с помощью MDS Explorer

  MDS Explorer - это OpenSource-проект, цель которого создание средства для доступа к Oracle MDS (Meta Data Services) репозиториям с помощью которого можно создавать, удалять, загружать, выгружать директории и файлы.
  На сайте проекта можно скачать исходники (в скомпилированном виде отсутствуют). В скомпилированном виде в одном jar-файле выкладываю здесь.
  Запуск:
  1. Выполнить следующую команду:
     java -Drepository.flavor=DB -jar MDSExplorer.jar  
    
    где DB - для доступа к репозиторию в БД;
        FILE - для доступа к репозиторию в файловой системе.
  2. Ввести параметры соединения со схемой MDS, затем нажать "Connect", выбрать нужный раздел (partition) и нажать "OK":
  3. В открывшемся окне можно выполнять действия по управлению структурой MDS: