Tuesday, 17 June 2014

Несколько слов о паттернах в Java EE

Начал читать недавно одну книгу о паттернах в Java EE, как они изменились и "как нынче стоит составлять дизайн"! Хочу отметить что нынче паттерны звучат банально, на них не стоит утыкаться и зацикливаться как некоторые авторы этого негласно требуют, можно просто следовать обще принятым принципам таким как например, DRY (Do not repeat yourself), инкапсуляция, разделение обязанностей, в общем все то что ведет нас к выгодной позиции.

Анемическая модель доменов - раскритикована как ни знаю что. Тем не менее она проста и удобна. На мой взгляд, втыкать туда вспомогательные методы к примеру относящиеся только к этой сущности и ее дочерним коллекциям, и не определяя зависимости к внешним факторам а также принимая во внимание что поведение этих методов-аксессуаров возможно таким и останется - это нормально. Ограничимся этим. Выполнять там имплементацию Builder уже сомнительно, уже теряется простота, но все же можно если там нет бизнес логики. EnttyManager к сущности отношение не имеет, ему там сидеть тем более ни к чему. Анемическая модель после этого или нет - это не важно. Главное удобно и сущность не теряет своей эластичности. Сущность часто сильно зависит по своим свойствам от модели БД (трогать которую иногда нельзя), они сами по себе носят не самый доступный характер, но это значит только то что при возможности внося новшество JPA в систему нужно стремиться к упрощению.
К примеру, тут итак модель запутанна, добавлять туда бизнес логику не всегда разумно в особенности если она диктует порядок сохранения, и ее можно оставить за пределами сущности:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
@Entity
@Inheritance(strategy=InheritanceType.SINGLE_TABLE)
@DiscriminatorValue("PFH.POINTABLE_SMBLOCK_TYPE")
public class GterPointableSmBlock extends GterSmall {

 @ManyToOne
 @JoinColumn(name="SMBLOCK_TYPE_ID_1")
 private PointableSmBlockType editableSmBlockType1;
 
 @ManyToOne
 @JoinColumn(name="SMBLOCK_TYPE_ID_2")
 private PointableSmBlockType editableSmBlockType2;
 
 @Column(name="ACTIVE")
 private int activeInd;
 
 @Column(name="AUDIT")
 private int auditNum;
 
 @Column(name="ROWSUID")
 private String rowId;
 
 @Column(name="CATSUID")
 private String cater;

Простенькие модельки, часто просто не в чем ином не нуждаются:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
@Entity
public class User {
 
 @Id
 @GeneratedValue(strategy=GenerationType.AUTO)
 private long id;
 
 private String username;
 
 private String first;
 
 private String last;

 public long getId() {
  return id;
 }

 public void setId(long id) {
  this.id = id;
 }

 public String getUsername() {
  return username;
 }

 public void setUsername(String username) {
  this.username = username;
 }

 public String getFirst() {
  return first;
 }

 public void setFirst(String first) {
  this.first = first;
 }

 public String getLast() {
  return last;
 }

 public void setLast(String last) {
  this.last = last;
 }

 @Override
 public int hashCode() {
  final int prime = 31;
  int result = 1;
  result = prime * result + ((first == null) ? 0 : first.hashCode());
  result = prime * result + ((last == null) ? 0 : last.hashCode());
  result = prime * result
    + ((username == null) ? 0 : username.hashCode());
  return result;
 }

 @Override
 public boolean equals(Object obj) {
  if (this == obj)
   return true;
  if (obj == null)
   return false;
  if (getClass() != obj.getClass())
   return false;
  User other = (User) obj;
  if (first == null) {
   if (other.first != null)
    return false;
  } else if (!first.equals(other.first))
   return false;
  if (last == null) {
   if (other.last != null)
    return false;
  } else if (!last.equals(other.last))
   return false;
  if (username == null) {
   if (other.username != null)
    return false;
  } else if (!username.equals(other.username))
   return false;
  return true;
 }
 
 

}

Такие паттерны как Service Facade, Service, вообще в принципе не несут сути в контексте Java EE. Сколько задач, столько и разновидностей, не может быть толкований на основе какой либо иной по мимо поставленной задачей производством и ее выполнения. Тем более о характеристиках таких как TransactionAttribute. Все очень индивидуально, просто раньше технология J2EE несла кучу недоработок, в обход которым были созданы продукты прогресса такие как DI (Dependency Injection), упрощенные EJB и паттерны уже как таковые ни чего не значат. Девелопер уже может больше времени уделять разработке бизнес логики с использованием полиморфизма как метод элегантной обрисовки процесса и.т.д, нежели заниматься демагогией о паттернах в сфере EE.     

Sunday, 15 June 2014

Учебное пособие struts2 на сервере Weblogic 10.3


Struts 2 – Weblogic 10.3.4 туториал.

Этот туториял, как то давно писал на английском, решил перевести на русский

Вот что нужно предварительно:
1 ) JDK 6
2) eclipse
3) weblogic server 10.3.4 or later
4) Ant 6

1)     Загрузите последний релиз struts 2 (http://struts.apache.org/).
2)     Распакуйте struts в какое нибудь вам приемлемое место к которому бедем оброщаться как к STRUTS_HOME.
3)     Создайте новый java проэкт в эклипсе и назовите его как вам нравиться ну а мы тут назовем его strutsApp. 








4)     Теперь разработаем build файл, который будет собирать части приложения в единый war архив. Вот этот build файл который я вытащил из другого проэкта и подкоректировал под наш (на дату внимания не обращайте )):


<?xml version="1.0" encoding="UTF-8"?>
<!-- ======================================================================
     Aug 21, 2011 11:58:33 AM                                                        

     This is our struts project.
                  
     iakoupov                                                               
     ====================================================================== -->
<project name="strutsApp" default="war" basedir=".">
    <description>
            This is the struts project.
    </description>
      
       <property name="wl.autodeploy.dir" value="C:\oracle\Middleware\user_projects\domains\strutsApp\autodeploy"/>
       <property name="strutsApp.war.name" value="strutsApp.war"/>
       <property name="strutsApp.ejb.name" value="strutsAppEJB.jar"/>


       <path id="war.classpath">
              <fileset dir="./WEB-INF/lib">
                     <include name="**/*.jar"/>
              </fileset>
             
              <fileset dir="C:\oracle\Middleware\wlserver_10.3\server\lib">
                     <include name="weblogic.jar"/>
              </fileset>
       </path>
      
       <path id="ejb.classpath">
                    
              <fileset dir="C:\oracle\Middleware\user_projects\domains\strutsApp\lib">
                     <include name="**/*.jar"/>
              </fileset>
      
              <fileset dir="C:\oracle\Middleware\wlserver_10.3\server\lib">
                     <include name="**/*.jar"/>
              </fileset>
             
              <fileset dir="C:\oracle\Middleware\modules">
                     <include name="javax.ejb_3.0.1.jar"/>
                     <include name="javax.jms_1.1.1.jar"/>
              </fileset>
       </path>

    <!-- =================================
          target: war             
         ================================= -->
    <target name="war" depends="" description="This is a struts project.">
      
      
       <antcall target="mkdirs"/>
        <antcall target="compileWar"/>
      
       <war destfile="${wl.autodeploy.dir}\${strutsApp.war.name}"
              webxml="./WEB-INF/web.xml">
              <classes dir="./classes"/>
              <lib dir="./WEB-INF/lib"/>
       </war>
      
      
    </target>
      
       <!-- =================================
                 target: EJB             
                ================================= -->
           <target name="ejb" depends="" description="">
             
             
              <antcall target="mkdirs"/>
               <antcall target="compileEJBs"/>
             
              <jar
                     destfile="${wl.autodeploy.dir}\${strutsApp.ejb.name}"
                     basedir="./classes">
                    
              </jar>
             
           </target>
      
       <target name="mkdirs" description="Creates required directories for compiation">
              <delete dir="./compile"/>
       <delete dir="./classes"/>
       <mkdir dir="./compile"/>
       <mkdir dir="./classes"/>
       </target>
      
       <!-- - - - - - - - - - - - - - - - - -
                 target: compileEJBs                     
                - - - - - - - - - - - - - - - - - -->
           <target name="compileEJBs">
              <javac srcdir="./src"
                     destdir="./classes"
                     classpathref="ejb.classpath"
                     debug="true" debuglevel="lines,vars,source">
                    
              </javac>
             
              <copy todir="./classes">
                  <fileset dir="src"
                           includes="**/*.properties" />
              </copy>
             
           </target>

    <!-- - - - - - - - - - - - - - - - - -
          target: compile                     
         - - - - - - - - - - - - - - - - - -->
    <target name="compileWar">
       <javac srcdir="./src"
              destdir="./classes"
              classpathref="war.classpath"
              debug="true" debuglevel="lines,vars,source">
             
       </javac>
      
       <copy todir="./classes">
           <fileset dir="src"
                    includes="**/*.xsl" />
       </copy>
    </target>

</project>
5)     Обратите внимание на autodeploy директорию, она указывает место расположения домена веблоджика. Если у вас есть какой нибудь домен, то можете указать его, если нет то следующий шаг рассказывает как таковой создать.

6)     Откойте weblogic configuration wizard. Выберете create new domain. Если хотите, выберете дополнительную опцию установки Web services ( я выбрал jax-ws extension, хот и нам это ни к чему но вот в бедещем...). Назовите домен как хотите, мы же для простоты назовем его strutsApp. Выберете user/passwords для консоля и запомните, лучше записать. Выберете JDK. Отметьте AdministrationServer. Выберете порт, удостоверившись что другие сервера на нем не бегут, вроде по умолчанию там 7001. Затем next и done.

7)    Теперь, чтоб не усложнять себе жизнь и не делать чего то с нуля, возьмем готовую програмку struts2 которая идет вместе с загрузкой библиотек struts 2 в качестве примера. Зайдите в STRUTS_HOME\apps. Распакуйте struts2-blank.war в той же папке. Я распаковал этот пример в папку struts2-blank, директории STRUTS_HOME\apps, то есть в STRUTS_HOME\apps\struts2-blank.

8)     В проэкте еклипса создайте папку Web-INF. Внутри “WEB-INF” другую и назовите ее “lib”. теперь в этот lib скопируйте все библиотеки из STRUTS_HOME\apps\struts2-blank\WEB-INF\lib.     

9)     Теперь давайте скопируем все нужные нам файлы из этой программы. План таков, чтобы построить проэкт из иcходного кода стратсовского примера, и после того как процесс формирования программы будет отлажен ничиная с исходников и заканчивая рабочим приложением, в будущем можно будет с легкостью вносить изменения, так как подготовка всегда занимает больше времени нежели сама разработка, а так-же вносить изменения всегда почти легче нежели писать с нуля (я не говорю о тех программах которые огромны но безнадежно запоренны изначально, в током случае может быть проще выкинуть и перписать по человечески, но это утопия так как начальство смотрит на вещи не всегда с перспективой кагого то будушего). Итак не будем распускать нюно-философию и вернемся к поставленной задаче. Скопирейте папку example в корень эклипс-проэкта, затем error и index jsps странички тоже туда, а вот web.xml из web-inf в web-inf проэкта, теперь скопируйте example.xml и struts.xml из src\java в папку src вашего проэкта. Теперь в папке src создайте новый package с названием example и скопируйте туда файлы из src\java\example. То есть мы просто передвигаем исходники в наш проэкт таким образом чтоб исходники не пришлось менять, это мы на потом оставим, на ваше усмотрение. Должно появиться куча ошибок компилирования, это из за того что исходники не находят для компеляции нужных им библиотек, ну вот мы им на них и укажем. Нажмите правой кнопкой мышки на проэкт и выберете properties, слева нажмите не Java Build Path, затем нажмите на таб libraries, затем нажмите на кнопку add jars справа (щас мы выберем необходимые для компеляции библиотеки), выберете свой проэкт затем web-inf а в нем lib и отметьте там все jar файлы. Нажмите там ok и все ошибки должны исчезнуть.
10)    Я повторяю, идея состоит в том что-бы запустить этот пример. Пришлось внести некоторые изменения в build.xml, по двум таргетам:


















<target name="war" depends="" description="This is a struts project.">
     
     
      <antcall target="mkdirs"/>
        <antcall target="compileWar"/>
     
      <war destfile="${wl.autodeploy.dir}\${strutsApp.war.name}"
            webxml="./WEB-INF/web.xml">
            <classes dir="./classes"/>
            <lib dir="./WEB-INF/lib"/>
            <fileset dir="."
               includes="**/*.jsp" />
                       
             <fileset dir="."
                  includes="**/*.html" />
                       
             <fileset dir="."
                  includes="**/*.xhtml" />
      </war>
     
     
    </target>
<target name="compileWar">
      <javac srcdir="./src"
            destdir="./classes"
            classpathref="war.classpath"
            debug="true" debuglevel="lines,vars,source">
           
      </javac>
     
      <copy todir="./classes">
          <fileset dir="src"
                   includes="**/*.xsl" />
           
            <fileset dir="src"
                   includes="**/*.xml" />
           
            <fileset dir="src"
                  includes="**/*.properties" />
      </copy>
</target>




11)  Запускаем build файл! При запуске, выберете target WAR. После удачног запуска, проверьте директорию autodeploy в домене вашего Weblogic-а. Вот директория, которую я проверял у себя: C:\oracle\Middleware\wlserver10.3\user_projects\domains\strutsApp\autodeploy тут должел быть ваш WAR архив. Открйте и проверьте что-бы все было на месте, в правильных папках и.т.д:







12)  Запустите Weblogic (в вашем домене есть папка bin и в нутри нее, startWeblogic.cmd и такой-же файл с .sh екстеншеном, если вы в винде то вам нежен cmd). После запуска вы должны увидеть log4j info записи в консоле эклклипса - это если вы сервер запускаете из эклипса (или в окне cmd если так).


13)  В браузере зайдите по адресу http://localhost:7002/strutsApp. У меня порт 7002, вы укажите свой. Заметьте что название WAR архива служит директорией адреса, это обычно всегда так. Вот что вы должны увидеть, и если вы это видете то запуск удался: struts is up and running. Hooray!