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

Ошибка "java.lang.UnsupportedOperationException: Remote JDBC disabled" и варианты её решения

Ошибка:
При попытке удалённого доступа к DataSource-у Weblogic-сервера генерируется следующая ошибка:
 java.lang.UnsupportedOperationException: Remote JDBC disabled  
      at weblogic.rjvm.ResponseImpl.unmarshalReturn(ResponseImpl.java:234)  
      at weblogic.rmi.cluster.ClusterableRemoteRef.invoke(ClusterableRemoteRef.java:348)  
      at weblogic.rmi.cluster.ClusterableRemoteRef.invoke(ClusterableRemoteRef.java:259)  
      at weblogic.jdbc.common.internal.RmiDataSource_1036_WLStub.getConnection(Unknown Source)  
      at oracle.integration.platform.blocks.event.saq.SAQRemoteBusinessEventConnection.createConnection(SAQRemoteBusinessEventConnection.java:122)  
      at oracle.integration.platform.blocks.event.saq.SAQRemoteBusinessEventConnection.enqueueEvent(SAQRemoteBusinessEventConnection.java:67)  
      at oracle.integration.platform.blocks.event.saq.SAQRemoteBusinessEventConnection.publishEvent(SAQRemoteBusinessEventConnection.java:54)  
      ...  
 Caused by: java.lang.UnsupportedOperationException: Remote JDBC disabled  
      at weblogic.jdbc.common.internal.JDBCServerHelperImpl.<clinit>(JDBCServerHelperImpl.java:50)  
      at weblogic.jdbc.common.internal.JDBCService.initialize(JDBCService.java:91)  
      at weblogic.jdbc.common.internal.JDBCService.start(JDBCService.java:138)  
      at weblogic.t3.srvr.SubsystemRequest.run(SubsystemRequest.java:64)  
      at weblogic.work.ExecuteThread.execute(ExecuteThread.java:256)  
      at weblogic.work.ExecuteThread.run(ExecuteThread.java:221)  
Причина:
Удалённый доступ к JDBC отключен в Weblogic Server.

Варианты решения:
Первый вариант:
  1. Перейти в директорию домена. Перейти в поддиректорию bin и изменить файл setDomainEnv.sh
  2. Найти свойство WLS_JDBC_REMOTE_ENABLED и изменить его значение с false на true:
     ...  
     WLS_JDBC_REMOTE_ENABLED="-Dweblogic.jdbc.remoteEnabled=true"  
     export WLS_JDBC_REMOTE_ENABLED  
     ...  
    
  3. Перестартовать все Managed-сервера домена.
Второй вариант:
  • Установить при запуске сервера системное свойство (как сделать см.здесь):
     -Dweblogic.jdbc.remoteEnabled=true  
    

воскресенье, 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);
        }
    }