Главная > OA Framework, Oracle e-Business Suite > Ant при разработке с использованием OAF


Ant при разработке с использованием OAF

При разработке проектов с использованием OAF и JDeveloper возникла необходимость частого переноса (или развертывания — deploy) приложений с одного экземпляра системы на другой.

Операция переноса состоит из пяти шагов:

  1. Компиляция java классов
  2. Перенос java классов на сервер приложений (в каталог $JAVA_TOP)
  3. Перенос xml файлов Entity Objects, View Objects, Application Modules ($JAVA_TOP)
  4. Импорт xml файлов Pages, Regions с помощью утилиты import
  5. Импорт xliff файлов

Проделав эту операцию пару раз вручную, решил все это дело автоматизировать.
Вся автоматизация построена на известном продукте Apache Ant.

Состоит из четырех файлов

  1. <project>.bat
  2. <project>.xml
  3. build.xml
  4. <project>.properties

, где <project> имя Вашего проекта.

В общих словах:

<project>.bat запускает ant, <project>.xml содержит то, что будет обрабатываться в build.xml (java файлы, xml файлы, xliff файлы, sql-команды)

build.xml содержит операции которые будут выполняться. Состоит из target’ов, которые производят операции над файлами из файла <project>.xml

<project>.properties содержит параметры для определенного экземпляра системы такие как пути, адреса хостов, имена пользователей, пароли

Детально:
Содержание файла .bat

-----Начало------------
ant -f build.xml -Dinstance=testinstance -Dproject=<project>

-----Конец-------------

Как видите запускается ant с build.xml файлом, параметром instance который равен например, «testinstance» и project который равен <project> в именах файлов. Параметр instance необходим для импорта в build.xml файла со значениями параметров данного экземпляра системы (файл под номером 4). Параметр project необходим так же для импорта в build.xml параметров данного проекта. Далее идет содержание файлов с пояснениями. Содержимое фалов относится к небольшому реальному проекту.

Содержание файла <project>.xml

---------------------------------------------------------Начало-------------------------------------------------------

<project name="concurrent" default="all">
<property name="project.name" value = "concurrent"/>

<property name="root.package" value="mycompany/oracle/apps/fnd/concurrent"/>

<!--SQL-команды для выполнения на сервере БД.-->
<property name="sql.1" value="insert into APPLSYS.FND_MENU_ENTRIES_TL (LANGUAGE, MENU_ID, ENTRY_SEQUENCE, LAST_UPDATE_DATE, LAST_UPDATED_BY, LAST_UPDATE_LOGIN, CREATION_DATE, CREATED_BY, PROMPT, DESCRIPTION, SOURCE_LANG)
values ('US', 67852, 7, to_date('09-04-2012 18:40:49', 'dd-mm-yyyy hh24:mi:ss'), 1090, 78995104, to_date('09-04-2012 18:40:49', 'dd-mm-yyyy hh24:mi:ss'), 1090, 'КЗ: Параллельные программы', 'Работа с параллельными программами', 'RU')"/>

<property name="sql.2" value="insert into APPLSYS.FND_MENU_ENTRIES_TL (LANGUAGE, MENU_ID, ENTRY_SEQUENCE, LAST_UPDATE_DATE, LAST_UPDATED_BY, LAST_UPDATE_LOGIN, CREATION_DATE, CREATED_BY, PROMPT, DESCRIPTION, SOURCE_LANG)
values ('RU', 67852, 7, to_date('09-04-2012 18:40:49', 'dd-mm-yyyy hh24:mi:ss'), 1090, 78995104, to_date('09-04-2012 18:40:49', 'dd-mm-yyyy hh24:mi:ss'), 1090, 'КЗ: Параллельные программы', 'Работа с параллельными программами', 'RU')"/>

<property name="sql.3" value="insert into APPLSYS.FND_MENU_ENTRIES (MENU_ID, ENTRY_SEQUENCE, LAST_UPDATE_DATE, LAST_UPDATED_BY, LAST_UPDATE_LOGIN, CREATION_DATE, CREATED_BY, SUB_MENU_ID, FUNCTION_ID, GRANT_FLAG)
values (67852, 7, to_date('09-04-2012 18:40:49', 'dd-mm-yyyy hh24:mi:ss'), 1090, 78995104, to_date('09-04-2012 18:40:49', 'dd-mm-yyyy hh24:mi:ss'), 1090, null, 40492, 'Y')"/>

<property name="sql.4" value="insert into APPLSYS.FND_FORM_FUNCTIONS (FUNCTION_ID, FUNCTION_NAME, LAST_UPDATE_DATE, CREATION_DATE, LAST_UPDATED_BY, CREATED_BY, LAST_UPDATE_LOGIN, TYPE, WEB_SECURED, WEB_ENCRYPT_PARAMETERS, MAINTENANCE_MODE_SUPPORT, WEB_HTML_CALL, CONTEXT_DEPENDENCE)
values (40492, 'KZT_FND_CONCURRENTS', to_date('09.04.2012 18:39', 'dd.mm.rrrr hh24:mi'), to_date('09.04.2012 18:39', 'dd.mm.rrrr hh24:mi'), 1090, 1090, 78995104, 'JSP', 'N', 'N', 'NONE', 'OA.jsp?page=/mycompany/oracle/apps/fnd/concurrent/webui/ConcurrentPG', 'RESP')"/>

<property name="sql.5" value="insert into APPLSYS.FND_PROFILE_OPTION_VALUES (APPLICATION_ID, PROFILE_OPTION_ID, LEVEL_ID, LEVEL_VALUE, LAST_UPDATE_DATE, LAST_UPDATED_BY, CREATION_DATE, CREATED_BY, LAST_UPDATE_LOGIN, PROFILE_OPTION_VALUE, LEVEL_VALUE_APPLICATION_ID, LEVEL_VALUE2)
values (1, 10941, 10001, 0, to_date('11-04-2012 10:55:53', 'dd-mm-yyyy hh24:mi:ss'), 1090, to_date('11-04-2012 10:25:19', 'dd-mm-yyyy hh24:mi:ss'), 1090, 78996469, '/appclone/appclone/CLONE_inst/apps/CLONE_appclone/logs/appl/conc/out', null, null)"/>

<property name="sql.6" value="insert into APPLSYS.FND_PROFILE_OPTIONS (APPLICATION_ID, PROFILE_OPTION_ID, PROFILE_OPTION_NAME, LAST_UPDATE_DATE, LAST_UPDATED_BY, CREATION_DATE, CREATED_BY, LAST_UPDATE_LOGIN, WRITE_ALLOWED_FLAG, READ_ALLOWED_FLAG, USER_CHANGEABLE_FLAG, USER_VISIBLE_FLAG, SITE_ENABLED_FLAG, SITE_UPDATE_ALLOWED_FLAG, APP_ENABLED_FLAG, APP_UPDATE_ALLOWED_FLAG, RESP_ENABLED_FLAG, RESP_UPDATE_ALLOWED_FLAG, USER_ENABLED_FLAG, USER_UPDATE_ALLOWED_FLAG, START_DATE_ACTIVE, SQL_VALIDATION, END_DATE_ACTIVE, HIERARCHY_TYPE, SERVER_ENABLED_FLAG, ORG_ENABLED_FLAG, SERVER_UPDATE_ALLOWED_FLAG, ORG_UPDATE_ALLOWED_FLAG, SERVERRESP_ENABLED_FLAG, SERVERRESP_UPDATE_ALLOWED_FLAG)
values (1, 10941, 'KZT_XML_TMP_PATH', to_date('11-04-2012 10:24:00', 'dd-mm-yyyy hh24:mi:ss'), 1090, to_date('11-04-2012 10:24:00', 'dd-mm-yyyy hh24:mi:ss'), 1090, 78996444, 'Y', 'Y', 'Y', 'Y', 'Y', 'Y', 'Y', 'Y', 'Y', 'Y', 'Y', 'Y', to_date('11-04-2012', 'dd-mm-yyyy'), null, null, 'SECURITY', 'N', 'N', 'N', 'N', 'N', 'N')"/>

<property name="sql.7" value="insert into APPLSYS.FND_NEW_MESSAGES (APPLICATION_ID, LANGUAGE_CODE, MESSAGE_NUMBER, MESSAGE_NAME, MESSAGE_TEXT, CREATION_DATE, CREATED_BY, LAST_UPDATE_DATE, LAST_UPDATED_BY, LAST_UPDATE_LOGIN, DESCRIPTION, TYPE, MAX_LENGTH, CATEGORY, SEVERITY, FND_LOG_SEVERITY)
values (1, 'RU', null, 'KZT_XML_PATH_NOT_FOUND', 'Значение профиля "КЗ: Путь для выгрузки/загрузки временных файлов" не задано. Задайте значение', to_date('11-04-2012 10:37:30', 'dd-mm-yyyy hh24:mi:ss'), 1090, to_date('11-04-2012 10:37:30', 'dd-mm-yyyy hh24:mi:ss'), 1090, 78996444, null, '30_PCT_EXPANSION_PROMPT', null, null, null, null)"/>

<!--Java файлы проекта-->
<fileset id="java.files" dir="${src.dir}/${root.package}">
<include name="server/ConcurrentAMImpl.java"/>
<include name="server/ConcurrentVOImpl.java"/>
<include name="server/ConcurrentVORowImpl.java"/>
<include name="server/XmlFileVOImpl.java"/>
<include name="server/XmlFileVORowImpl.java"/>
<include name="server/UploadFileVOImpl.java"/>
<include name="server/UploadFileVORowImpl.java"/>
<include name="server/CommonUtils.java"/>
<include name="server/DataTable.java"/>
<include name="server/ReportData.java"/>
<include name="server/XMLReportData.java"/>
<include name="server/DOMSerializer.java"/>
<include name="webui/ConcurrentCO.java"/>
</fileset>

<!--Class файлы проекта-->
<fileset id="class.files" dir="${classes.dir}">
<include name="${root.package}/server/ConcurrentAMImpl.class"/>
<include name="${root.package}/server/ConcurrentVOImpl.class"/>
<include name="${root.package}/server/ConcurrentVORowImpl.class"/>
<include name="${root.package}/server/XmlFileVOImpl.class"/>
<include name="${root.package}/server/XmlFileVORowImpl.class"/>
<include name="${root.package}/server/UploadFileVOImpl.class"/>
<include name="${root.package}/server/UploadFileVORowImpl.class"/>
<include name="${root.package}/server/CommonUtils.class"/>
<include name="${root.package}/server/DataTable.class"/>
<include name="${root.package}/server/ReportData.class"/>
<include name="${root.package}/server/XMLReportData.class"/>
<include name="${root.package}/server/ReportData$QueryTable.class"/>
<include name="${root.package}/server/DOMSerializer.class"/>
<include name="${root.package}/webui/ConcurrentCO.class"/>
</fileset>

<!--xml файлы проекта такие как (AM, VO, EO)-->
<fileset id="server.files" dir="${src.dir}">
<include name="${root.package}/server/ConcurrentAM.xml"/>
<include name="${root.package}/server/ConcurrentVO.xml"/>
<include name="${root.package}/server/XmlFileVO.xml"/>
<include name="${root.package}/server/UploadFileVO.xml"/>
</fileset>

<!--xml файлы проекта такие как (PG, RN)-->
<fileset id="webui.files" dir="${src.dir}">
<include name="${root.package}/webui/ConcurrentPG.xml"/>
</fileset>

<!--xliff файлы проекта-->
<fileset id="xliff.files" dir="${src.dir}">
<include name="${root.package}/webui/ConcurrentPG.xlf"/>
</fileset>

</project>

---------------------------------------------------------Конец---------------------------------------------------------

Как видите в <project>.xml нет никаких операций, только перечисление файлов.

Содержание файла build.xml

---------------------------------------------------------Начало--------------------------------------------------------- 

<project name="oaf.builder" default="all">

<taskdef resource="net/sf/antcontrib/antlib.xml"/>
<!--Импорт параметров экземпляра системы, на который хотим переносить свое приложение (файл №4)-->
<property file="${instance}.properties"/>

<property name="project.name" value = "concurrent"/>

<!--Необходимые пути для ссылки на библиотеки и т.п.-->
<property name="jdev.dir" value="C:/jdev"/>
<property name="base.dir" value="C:/jdev/jdevhome/jdev"/>
<property name="src.dir" value="${base.dir}/myprojects"/>
<property name="classes.dir" value="${base.dir}/myclasses"/>
<property name="jdbc.lib.dir" value="${jdev.dir}/jdevbin/jdbc/lib"/>
<property name="bc4j.lib.dir" value="${jdev.dir}/jdevbin/bc4j/lib"/>
<property name="uix2.lib.dir" value="${jdev.dir}/jdevbin/jdev/appslibrt"/>

<!--Импорт параметров проекта (файл №2)-->
<import file="${project}.xml"/>

<!--Определяем библиотеки OAF-->
<path id="class.path">
<pathelement location="${uix2.lib.dir}\fwk.zip"/>
<pathelement location="${uix2.lib.dir}\fwkjbo.zip"/>
<pathelement location="${uix2.lib.dir}\aolj.jar"/>
<pathelement location="${uix2.lib.dir}\uix2.jar"/>
<pathelement location="${uix2.lib.dir}\svc.zip"/>
<pathelement location="${bc4j.lib.dir}\bc4jmt.jar"/>
<pathelement location="${bc4j.lib.dir}\bc4jdomorcl.jar"/>
<pathelement location="${jdbc.lib.dir}\ojdbc14.jar"/>
<pathelement location="${jdbc.lib.dir}\ojdbc14dms.jar"/>
<pathelement location="${jdbc.lib.dir}\orai18n.jar"/>
</path>

<!--Если instance="prod" т.е. у меня это прзнак того, что переносим на "боевой" сервер, то устаналиваем is.prod="prod"
для дальнейшего использования, иначе этот параметр остается пустым-->
<target name="init" description="Initialize">
<condition property="is.prod">
<equals arg1="${instance}" arg2="prod"/>
</condition>
</target>

<!--И здесь смотрим, если параметр is.prod инициализирован, то просим ввести пароли для APPS и APPLMGR, иначе пароли берутся из файла instance.xml-->
<target name="set.password" depends="init" if="is.prod" description="Set production password">
<input message="Please enter APPS password:" addproperty="db.password">
<handler classname="org.apache.tools.ant.input.SecureInputHandler"/>
</input>
<input message="Please enter APPLMGR password:" addproperty="appl.password">
<handler classname="org.apache.tools.ant.input.SecureInputHandler"/>
</input>
</target>

<!--Компилируем Java файлы, указанные в файле <project>.xml в параметре java.files-->
<target name="compile" description="Compile source java files">
<!--Удаляем предыдущие версии class файлов-->
<delete dir="${classes.dir}/${root.package}"/>

<!--Конвертируем список Java файлов в строку с разделителем ","-->
<pathconvert targetos="unix" pathsep="," property="java.files" refid="java.files">
<map from="${src.dir}/" to=""/>
</pathconvert>

<!--Компилируем-->
<javac includes="${java.files}" destdir="${classes.dir}" target="1.5" encoding="UTF-8" includeantruntime="false" includejavaruntime="false">
<classpath refid="class.path"/>
<src path="${src.dir}"/>
</javac>
</target>

<!--Переносим все необходимое на сервер-->
<target name="deploy" depends="compile, set.password" description="Upload files to OA Server">
<!--Копируем файлы из каталога исходников в каталог "типа" out (на клиентской машине пока)-->
<copy todir="${classes.dir}" flatten="false">
<fileset refid="server.files"/>
<fileset refid="webui.files"/>
<fileset refid="xliff.files"/>
</copy>

<!--Копируем class файлы и xml файлы типа AM, VO, EO на сервер. Параметры подключения и каталог-приемник указаны в файле <project>.properties-->
<scp todir="${appl.user}:${appl.password}@${appl.host}:${java.top}" trust="true">
<fileset refid="class.files"/>
<fileset refid="server.files"/>
</scp>

<!--Импортируем xml файлы типа PG, RN. Параметры подключения указаны в файле <project>.properties-->
<for param="file">
<path>
<fileset refid="webui.files"/>
</path>
<sequential>
<echo message="Importing XML file"/>
<exec executable="${jdev.dir}\jdevbin\oaext\bin\import.bat">
<arg value="@{file}"/>
<arg value="-rootdir"/>
<arg value="${src.dir}"/>
<arg value="-username"/>
<arg value="${db.user}"/>
<arg value="-password"/>
<arg value="${db.password}"/>
<arg value="-dbconnection"/>
<arg value="${db.host}:${db.port}:${db.sid}"/>
<arg value="-rootPackage"/>
<arg value="/"/>
</exec>
</sequential>
</for>

<!--Импортируем xliff файлы. Параметры подключения указаны в файле <project>.properties-->
<for param="file">
<path>
<fileset refid="xliff.files"/>
</path>
<sequential>
<echo message="Importing XLIFF file"/>
<exec executable="${jdev.dir}\jdevbin\oaext\bin\xliffimport.bat">
<arg value="@{file}"/>
<arg value="-username"/>
<arg value="${db.user}"/>
<arg value="-password"/>
<arg value="${db.password}"/>
<arg value="-dbconnection"/>
<arg value="${db.host}:${db.port}:${db.sid}"/>
</exec>
</sequential>
</for>

<!--Выделяем все параметры у которых имя начинается на "sql."-->
<propertyselector property="sql" match="sql.*"/>

<!--И подставляем их содержимое в команду sql в цикле-->
<for list="${sql}" param="sql.property">
<sequential>
<sql driver="oracle.jdbc.driver.OracleDriver" url="jdbc:oracle:thin:@${db.host}:${db.port}:${db.sid}" userid="${db.user}" password="${db.password}" onerror="continue" classpathref="class.path">
${@{sql.property}}
</sql>
</sequential>
</for>

</target>

<!--"Передергиваем" Apache OACore для вступления в силу перенесенных файлов-->
<target name="bounce.apache" depends="deploy, bounce.apache.only" description="Bounce apache server">
</target>

<!--Отдельное задание для "передергивания" только Apache OACore без параметра depends-->
<target name="bounce.apache.only" description="Bounce apache server">
<delete file="${src.dir}/bounceapach.sh"/>
<!--echo file="bounceapach.sh" append="true" message="sh ${admin.scripts.home}/adapcctl.sh stop${line.separator}"/-->
<echo file="bounceapach.sh" append="true" message="sh ${admin.scripts.home}/adoacorectl.sh stop${line.separator}"/>
<!--echo file="bounceapach.sh" append="true" message="sh ${admin.scripts.home}/adapcctl.sh start${line.separator}"/-->
<echo file="bounceapach.sh" append="true" message="sh ${admin.scripts.home}/adoacorectl.sh start${line.separator}"/>
<sshexec host="${appl.host}" username="${appl.user}" password="${appl.password}" commandResource="bounceapach.sh" trust="true"/>
<delete file="${src.dir}/bounceapach.sh"/>
</target>

<target name="all" depends="bounce.apache"/>
</project>
---------------------------------------------------------Конец---------------------------------------------------------

Содержание файла <instance>.properties

---------------------------------------------------------Начало---------------------------------------------------------

db.host=192.168.192.192
db.user=apps
db.password=apps
db.port=1538
db.sid=test
appl.host=192.168.192.193
appl.user=applmgr
appl.password=applmgr
java.top=Необходимо прописать путь $JAVA_TOP
appl.top=Необходимо прописать путь $APPL_TOP
admin.scripts.home=Необходимо прописать путь $ADMIN_SCRIPTS_HOME
---------------------------------------------------------Конец--------------------------------------------------------

В этом файле все просто. Можно было бы его тоже оформить как ant’овский xml файл, но пока у меня так.

Типа того.

Похожие записи:

  1. profik777
    6 Сентябрь 2012 в 11:18 | #1

    Подскажите, почему необходим «Импорт xml файлов Pages, Regions с помощью утилиты import»? Почему нельзя просто перенести их в соответствующий каталог на сервере?

  2. 6 Сентябрь 2012 в 15:24 | #2

    @profik777
    Через XMLImporter происходит запись данных в MDS репозиторий (заполняются таблицы JDR_ATTRIBUTES, JDR_COMPONENTS, JDR_PATHS, JDR_ATTRIBUTES_TRANS).

  3. profik777
    7 Сентябрь 2012 в 14:37 | #3

    Огромное Вам спасибо за неоценимую помощь! :-)

  1. Пока что нет уведомлений.