Показаны сообщения с ярлыком java. Показать все сообщения
Показаны сообщения с ярлыком java. Показать все сообщения

среда, 1 октября 2014 г.

Вторая часть освоения SOA

Требуется изучить:

Выполнить tutorial. Есть следующие полезные книги:
  • Getting Started With Oracle SOA Suite 11gR1 (главы 1-10,13-15,17)
  • Oracle SOA Suite 11g R1 Developers Guide (главы 1-8,11,13-14,18-21)
  • WS-BPEL 2.0 for SOA Composite Applications with Oracle SOA Suite 11g (главы 1-7 включительно)
Книги однотипные, главы связанные с BAM (Business Activity Monitorung) и OSB (Oracle Service Bus) пока не рассматриваем. Первые две книги содержат tutorial-ы. Пройдите от начала до конца одину из них (см. указанные главы). Обрати внимание, что оба tutorial-а по немного более старой версии SOA (например по 11.1.1.5), хотя на данный момент чаще всего используется версии 11.1.1.6 и 11.1.1.7 - поэтому скриншоты в книгах могут немного не совпадать.
После завершения tutorial просмотреть остальные книги на непроработанный/незатронутый функционал.

Выполнить задание:

  1. Создать две JMS Queue в Weblogic;
  2. Создать MDB, который перекладывает сообщения из одной очереди в другую;
  3. Развернуть на сервере и протестировать.

Полезные ссылки:

  1. Рекомендую использовать официальный developers guide по Oracle SOA, как справочник.
  2. Хороший блог по Oracle SOA на русском языке
  3. Блоги на английском:

вторник, 30 сентября 2014 г.

Первая часть освоения SOA

Требуется изучить:

Книг по XML много, в том числе и на русском. Дополнительно полезно знать XQuery. Нужно понимание функциональности и возможностей XQuery по сравнению с XSL. Рекомендую книгу «W3C XML: Xquery от экспертов. Руководство по языку запросов» или в оригинале «XQuery from the Experts: A Guide to the W3C XML Query Language».

  • Weblogic. Требуется разобраться:
    • Как минимум, в следующих технологиях:
      • JMS (Java Message Service)
      • MDB (Message Driven Bean)
      • JTA & JTS (Java Transaction API & Java Transaction Service)
    • В основах администрирования.

Полезные ссылки:

понедельник, 6 января 2014 г.

Планировщик заданий в Weblogic Server

Реализовать планировщик заданий можно, как средствами встроенных в операционную систему(ОС) планировщиков заданий так и встроенных СУБД, но при изменении ОС (например, с Windows на AIX) либо изменении СУБД (например, с Oracle на MySQL) потребуется переработка компонента планировщика. Рассмотрим реализацию планировщика заданий работающего внутри Weblogic Server, который не зависит от ОС и СУБД.
Данный планировщик представляет собой простейшее Web-приложение и будет выполнять задачу через каждые 5 секунд, а задача при выполнении будет писать в лог строку с временем выполнения (никто не запрещает сделать более сложную логику). А так же будет создан сервлет для управления заданием (действия - остановить выполнение и запустить выполнение). Более того при создании не будут использоваться внешние библиотеки, только те которые есть в Weblogic Server.
  1. Открываем Oracle JDeveloper и создаём новое приложение (с именем SampleScheduler):
  2. Затем добавляем в проект необходимые библиотеки.
  3. Создаём новый класс для описания задания(с именем HelloWorldJob):
     package com.blogspot.stan1slav.sample.jobs;  
       
     import commonj.timers.CancelTimerListener;  
     import commonj.timers.Timer;  
     import commonj.timers.TimerListener;  
       
     import java.io.Serializable;  
       
     import java.util.Date;  
       
     public class HelloWorldJob implements Serializable, TimerListener,  
                        CancelTimerListener {  
       private Date timerDate = null;  
       
       public HelloWorldJob() {  
         super();  
       }  
       
       public void timerExpired(Timer timer) {  
         timerDate = new Date(timer.getScheduledExecutionTime());  
         System.out.println("HelloWorldJob timer expired called on " +  
                   timerDate);  
       }  
       
       public void timerCancel(Timer timer) {  
         timerDate = new Date(timer.getScheduledExecutionTime());  
         System.out.println("HelloWorldJob timer cancelled called on " +  
                   timerDate);  
       }  
     }  
    
    Следует обратить внимание на выделенное красным, это те классы которые должны быть имплементированы и методы которые должны быть реализованы (один при срабатывании задачи и другой для отмены/остановки задачи). Инициализацию задания можно вынести в конструктор.
  4. Создаём сервлет для старта/остановки задания, а так же автозапуска:
     package com.blogspot.stan1slav.sample;  
       
     import com.blogspot.stan1slav.sample.jobs.HelloWorldJob;  
       
     import commonj.timers.Timer;  
     import commonj.timers.TimerManager;  
       
     import java.io.IOException;  
     import java.io.PrintWriter;  
       
     import java.util.Date;  
       
     import javax.naming.InitialContext;  
       
     import javax.servlet.ServletConfig;  
     import javax.servlet.ServletException;  
     import javax.servlet.http.HttpServlet;  
     import javax.servlet.http.HttpServletRequest;  
     import javax.servlet.http.HttpServletResponse;  
       
     public class JobsServlet extends HttpServlet {  
       private Timer helloWorldJobTimer = null;  
       private TimerManager tm = null;  
       
       public void init(ServletConfig config) throws ServletException {  
         super.init(config);  
         System.out.println("InitJobsServlet is initialized ");  
       
         try {  
           InitialContext ic = new InitialContext();  
           tm = (TimerManager)ic.lookup("java:comp/env/tm/TimerManager");  
           helloWorldJobTimer =  
               tm.schedule(new HelloWorldJob(), new Date(), 5000); //5 seconds  
         } catch (Exception ne) {  
           ne.printStackTrace();  
         }  
       }  
       
       public void service(HttpServletRequest req,  
                 HttpServletResponse res) throws IOException {  
         res.setContentType("text/html");  
         PrintWriter out = res.getWriter();  
         out.println("<h4>JobsServlet is working!</h4>");  
         String cmd = req.getParameter("cmd");  
         if (cmd != null && cmd.equals("cancel") && helloWorldJobTimer != null) {  
           helloWorldJobTimer.cancel();  
           helloWorldJobTimer = null;  
         }  
         if (cmd != null && cmd.equals("start") && helloWorldJobTimer == null) {  
           helloWorldJobTimer =  
               tm.schedule(new HelloWorldJob(), new Date(), 5000);  
         }  
         if (helloWorldJobTimer != null) {  
           out.println("<h6>HelloWorldJob started</h6>");  
         } else {  
           out.println("<h6>HelloWorldJob calceled</h6>");  
         }  
       }  
     }  
    
  5. В web.xml прописать ссылку на ресурс (т.е. на наш TimerManager):
     <?xml version = '1.0' encoding = 'UTF-8'?>  
     <web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"  
          xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"  
          version="2.5" xmlns="http://java.sun.com/xml/ns/javaee">  
      <servlet>  
       <servlet-name>JobsServlet</servlet-name>  
       <servlet-class>com.blogspot.stan1slav.sample.JobsServlet</servlet-class>  
       <load-on-startup>100</load-on-startup>  
      </servlet>  
      <servlet-mapping>  
       <servlet-name>JobsServlet</servlet-name>  
       <url-pattern>/jobsservlet</url-pattern>  
      </servlet-mapping>  
      <resource-ref>  
       <res-ref-name>tm/TimerManager</res-ref-name>  
       <res-type>commonj.timers.TimerManager</res-type>  
       <res-auth>Container</res-auth>  
       <res-sharing-scope>Unshareable</res-sharing-scope>  
      </resource-ref>
     </web-app>  
    
  6. Деплоим на сервер (как WAR-архив) и проверяем работоспособность (смотрим в out-лог сервера)
    1. Задание выполняется после деплоя:
    2. С использованием сервлета остановим выполнение задания (для этого при вызове добавляем ?cmd=cancel):
    3. В логе появилась запись об остановке (отмене) задания:
    4. С использованием сервлета стартуем снова задание (для этого при вызове добавляем ?cmd=start):
    5. В логе появились записи о выполнении задания:
Полезная информация:

воскресенье, 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 - проект содержащий данный пример.

суббота, 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);
        }
    }
    

воскресенье, 22 апреля 2012 г.

Рекомендации по настройке JVM для Weblogic Server в промышленном окружении

Внимание: описанные ниже рекомендации являются общими без учёта специфики конкретных приложений выполняющихся на сервере приложений Weblogic (например: некоторые фреймворки генерируют большое количество временных объектов, для этого случая, рекомендуется сделать размер nursery больше чем в общей рекомендации, но после проведения мониторинга JVM).

Общие рекомендации для любой JVM:
  • Установите одинаковый размер для initial heap size (параметр -Xms) и maximum heap size (параметр -Xmx);
  • Установить размер heap-а немного больше того, с которого нагрузочные тесты перестают получают исключение Out-of-Memory;
  • Не устанавливайте суммарный размер heap-а всех сервером на физической машине (с точки зрения ОС) больше чем 75% доступной памята.
Рекомендации для JRockit JVM:
  • Установите размер nursery (параметр -Xns) примерно 25-40% от размера heap-а;
  • Установите приоритетный уровень (параметр -XgcPrio) для сборщика мусора на значение по-умолчанию, т.е. throughput.
Рекомендации для Sun JVM:
  • Установите одинаковый размер для initial New Space (параметр -XX:NewSize) и maximum New Space (параметр -XX:MaxNewSize);
  • Установите значение New Space примерно 25% от размера heap-а;
  • Установите Survivor Ratio (параметр -XX:SurvivorRatio) значение 8.

четверг, 5 апреля 2012 г.

Поиск Java-класса в директории

Для поиска java-класса по всем jar в директории и поддиректориях можно воспользоваться утилитой JarScan (автор Geoff Yaworski). Загрузить её можно с сайта автора или отсюда.

Пример использования:
 $ java -jar jarscan.jar -dir /opt -class weblogic.jdbc.sqlserver.SQLServerDriver
  где /opt - директория для поиска;
       weblogic.jdbc.sqlserver.SQLServerDriver - имя класса.

пятница, 22 апреля 2011 г.

Изменение настроек JVM для домена Weblogic

Описание: Linux и Weblogic 10.3.4.
  • Старт серверов без использования NodeManager.:
    1. Залогиниться на сервер.
    2. Для смены JVM (JRockit млм HotSpot) выставить значание переменной JAVA_VENDOR:
      $ JAVA_VENDOR=Oracle #Для JRockit  
      $ JAVA_VENDOR=Sun    #Для HotSpot  
      $ export JAVA_VENDOR  
      
    3. Выставить желаемое значение через переменную USER_MEM_ARGS, например:
      $ USER_MEM_ARGS='-Xms1024m -Xmx1024m -XX:CompileThreshold=8000 -XX:PermSize=128m -XX:MaxPermSize=512m'  
      $ export USER_MEM_ARGS  
      
    4. Стартовать AdminServer или ManagedServer. Если JVM-параметры доменов отличаются, то рекомендую создать отдельные стартовые скрипты для каждого из ManagedServer-ов и AdminServer-а, например startAdminServer.sh:
       #!/bin/sh  
       USER_MEM_ARGS='-Xms1024m -Xmx1024m -XX:CompileThreshold=8000 -XX:PermSize=128m -XX:MaxPermSize=512m'  
       export USER_MEM_ARGS  
       JAVA_VENDOR=Sun  
       export JAVA_VENDOR
       #Start AdminServer    
       ./startWebLogic.sh  
      
  • Старт серверов с использованием NodeManager и через Weblogic Administration Console:
    1. Залогиниться в Weblogic Administration Console.
    2. Перейти в конфигурацию сервера (Имя_домена->Environment->Servers->Имя_сервера).
    3. Перейти во вкладку Configuration->Server Start.
    4. Заполнить поля Arguments и Java Vendor.

вторник, 19 апреля 2011 г.

Проблема в Oracle JDeveloper 11.1.1.4 при автогенерации HumanTask...

Описание: создадим простой BPM-проект с двумя HumanTask-ами и одной ролью (с несколькими ролями ситуация подобна этой).

1. Запустим JDeveloper.
2. Создадим новый BPM Application.

     Введите наименование проекта. Далее "Next":

     Далее "Finish":


     Далее предлагается создать BPM-процесс:


     Далее "Next":

3. Сгенерировался BPM-процесс.


4. Добавим ещё один UserTask.


5. Создадим определение UserTask-ов.

     UserTask1:

     UserTask2:

6. Сгенерируем формы пользовательского интерфейса с помощью автогенератора.

     UserTask1:


     UserTask2: аналогично UserTask1.

7. Получилось три проекта в нашем TestApplication: собственно BPM-проект и два Taskflow-проекта(HumanTask-проекта).

8. Задеплоим TestApplication на сервер BPM Suite.


     Далее "Next":

     Выбираем все TaskFlow-проекты. Далее "Next":

     Далее "Finish"

9. Заходим в BPM Workspace
9.1. Инициируем процесс.

Отправляем дальше:

Получаем первую ошибку:

9.2. Переходим на вторую задачу и получаем ошибку:

В чём причина этих ошибок???
Первая ошибка: автоматически не создалась страница Empty1.jspx
Вторая ошибка: при автогенерации форм для HumanTask-ов они создаются в одном и том же пакете и при деплое приложения возникает конфликт, который проявляется как "Error 500--Internal Server Error"

10. Исправление ошибок.
10.1. Первая ошибка:
10.1.1. Перейти в первый TaskFlow-проект в "Web Content"->"Page Flows"->"adfc-config".


10.1.2. Создайте Empty1.jspx дважды кликнув на эту страницу.


10.1.3. Аналогично с вторым TaskFlow-проектом.

10.2. Вторая ошибка:

10.2.1. Перейти в первый TaskFlow-проект в "Application Sources".


10.2.2. Провести рефакторинг пакета.


     Далее:

10.2.3. Открыть DataBindings.cpx и перейти на закладку "Source"


10.2.4. Изменить данный файл (см. выделение красным)


10.2.5. Удалить сгенерированные классы с прошлой сборки (удалить все внутри папки classes).

10.2.6. Аналогично с вторым TaskFlow-проектом.

11. Передеплоить TestApplication на сервер BPM Suite.

вторник, 22 марта 2011 г.

Включение Java-плагина для Firefox в Linux

Допущение: в данном примере версия JRE 6.0_24

1. Установить, если не установлена JRE.
2. Выполнить:
 [root@server1~]# cd /usr/lib/mozilla/plugins  
 [root@server1~]# ln -s /usr/java/jre1.6.0_24/plugin/i386/ns7/libjavaplugin_oji.so .  
3. Готово.

вторник, 2 июня 2009 г.

Пример простейшего MDB-компонента

Ниже пример MDB-компонента который слушает очередь (в этом примере jms/TestQueue) и выводит содержимое сообщения в лог-сервера:
 import javax.ejb.ActivationConfigProperty;  
 import javax.ejb.EJBException;  
 import javax.ejb.MessageDriven;  
 import javax.jms.Message;  
 import javax.jms.MessageListener;  
 import javax.jms.TextMessage;  
 @MessageDriven(  
 activationConfig = {  
 @ActivationConfigProperty(propertyName="destinationType", propertyValue="javax.jms.Queue") ,  
 @ActivationConfigProperty(propertyName="connectionFactoryJndiName",propertyValue="jms/JMSConnectionFactory"),  
 @ActivationConfigProperty(propertyName="destinationJndiName", propertyValue="jms/TestQueue")  
 }  
 ,mappedName="jms/TestQueue"  
 )  
 public class TestMDBBean implements MessageListener {  
   public void onMessage(Message message) {  
     try {  
       if (message instanceof TextMessage) {  
         TextMessage msg = (TextMessage)message;  
         System.out.println("Message arrived:");  
         System.out.println(msg.getText());  
         System.out.println("\n");  
       }  
     } catch (Exception e) {  
       throw new EJBException(e.toString());  
     }  
   }  
 }