| <?xml version="1.0"?> |
| <!-- |
| Licensed to the Apache Software Foundation (ASF) under one |
| or more contributor license agreements. See the NOTICE file |
| distributed with this work for additional information |
| regarding copyright ownership. The ASF licenses this file |
| to you under the Apache License, Version 2.0 (the |
| "License"); you may not use this file except in compliance |
| with the License. You may obtain a copy of the License at |
| |
| http://www.apache.org/licenses/LICENSE-2.0 |
| |
| Unless required by applicable law or agreed to in writing, |
| software distributed under the License is distributed on an |
| "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| KIND, either express or implied. See the License for the |
| specific language governing permissions and limitations |
| under the License. |
| --> |
| |
| <document> |
| |
| <properties> |
| <title>Migrating from 4.0 to 5.0</title> |
| </properties> |
| |
| <body> |
| |
| <section name="Introduction"> |
| <p> |
| This document describes the basic steps needed to migrate an |
| application written for Turbine 4.0 to Turbine 5.0. |
| </p> |
| <p> |
| Migrating from Turbine 4.0 to Turbine 5.0 is mostly a task of |
| updating any references to commons-config and insuring that you |
| are using Parts for file upload rather than the old FileItem object. |
| </p> |
| </section> |
| |
| |
| <section name="Updating configuration"> |
| |
| <subsection name="Log4j changes"> |
| <p> |
| TurbineResources.properties have changed making it less verbose |
| to point to the log4j config file. |
| |
| Secondly, we have upgraded to Log4j2. We still keep the file as is (i.e. outside classpath), as this is what Turbine did all the way. |
| |
| Old config line: |
| <source> |
| <![CDATA[ |
| |
| # ------------------------------------------------------------------- |
| # |
| # L O G 4 J - L O G G I N G |
| # |
| # ------------------------------------------------------------------- |
| |
| log4j.file = WEB-INF/conf/log4j.properties |
| |
| ]]> |
| </source> |
| |
| New config line: |
| <source> |
| <![CDATA[ |
| # ------------------------------------------------------------------- |
| # |
| # L O G 4 J 2 - L O G G I N G |
| # |
| # ------------------------------------------------------------------- |
| |
| log4j.file = log4j2.xml |
| ]]> |
| </source> |
| |
| </p> |
| |
| </subsection> |
| |
| <subsection name="Setting character encoding"> |
| <p> |
| The default character encoding typically should be set |
| by your servlet container. For example, in Tomcat you can |
| update the server.xml in the following way to force URI connections |
| to be encoded in UTF-8. |
| </p> |
| |
| <source> |
| <![CDATA[ |
| <!-- Define a non-SSL HTTP/1.1 Connector on port 8080 --> |
| <Connector port="8080" maxHttpHeaderSize="8192" |
| maxThreads="150" minSpareThreads="25" maxSpareThreads="75" |
| enableLookups="false" redirectPort="8443" acceptCount="100" |
| connectionTimeout="20000" disableUploadTimeout="true" |
| URIEncoding="UTF-8" |
| /> |
| ]]> |
| </source> |
| |
| <p> |
| However, earlier versions of Apache Turbine allowed you to override this |
| value by setting the input.encoding property in your TurbineResources.properties file. |
| </p> |
| |
| <p> |
| With Turbine 5.0, you can still accomplish this same behavior, but you need |
| to make sure that you have added the encoding valve to the turbine-classic-pipeline.xml |
| to enable it. |
| </p> |
| |
| <p> |
| In TurbineResources.properties, you can set the following parameter: |
| </p> |
| |
| <source> |
| <![CDATA[ |
| input.encoding = UTF-8 |
| ]]> |
| </source> |
| |
| <p> |
| But it will not be picked up unless you edit the pipeline valves |
| to read as follows. Note that ORDER does matter if you are not |
| seeing the behavior you expected. |
| </p> |
| |
| <source> |
| <![CDATA[ |
| <pipeline name="default"> |
| <valves> |
| |
| <!-- Use this valve to enable use of the input.encoding |
| parameter defined in your TurbineResources.properties file --> |
| <valve>org.apache.turbine.pipeline.DefaultSetEncodingValve</valve> |
| |
| <valve>org.apache.turbine.pipeline.DetermineActionValve</valve> |
| <valve>org.apache.turbine.pipeline.DetermineTargetValve</valve> |
| <valve>org.apache.turbine.pipeline.DefaultSessionTimeoutValve</valve> |
| <valve>org.apache.turbine.pipeline.DefaultLoginValve</valve> |
| <valve>org.apache.turbine.pipeline.DefaultSessionValidationValve</valve> |
| <valve>org.apache.turbine.pipeline.DefaultACLCreationValve</valve> |
| <valve>org.apache.turbine.pipeline.ExecutePageValve</valve> |
| <valve>org.apache.turbine.pipeline.CleanUpValve</valve> |
| <valve>org.apache.turbine.pipeline.DetermineRedirectRequestedValve</valve> |
| </valves> |
| </pipeline> |
| ]]> |
| </source> |
| |
| </subsection> |
| </section> |
| |
| |
| <section name="Migrating to Functioal Interfaces and Rundata"> |
| |
| <p>Functional interfaces are now used instead of abstract classes. Rundata should be removed and instead of PipelineData used, but we keep it for now. |
| As a result <strong>AbstractValve was removed</strong> and with it the method <strong>getRunData(pipelineData)</strong> is gone. |
| You may retrieve the Rundata casted object now with <strong>pipelineData.getRunData()</strong>. |
| </p> |
| |
| <source> |
| <![CDATA[ |
| // old |
| // RunData rundata = getRunData(pipelineData) |
| RunData rundata = pipelineData.getRunData(); |
| |
| ]]> |
| </source> |
| |
| <p> |
| Assembler derived classes in package org.apache.turbine.modules (Action, LayoutScreen, Navigation, Page, ..) |
| are now declared as java functional interfaces instead of abstract classes. |
| Using them in child classes might be as easy as replacing <strong>extends</strong> with <strong>implements</strong> keyword in class declaration. |
| Remark: Method signature containing checked exceptions were not changed. To use Java 8 functional lamda functions you may |
| catch and rethrow them wrapped into a RuntimeException. |
| </p> |
| |
| <source> |
| <![CDATA[ |
| |
| // old |
| // class MyAction extends Action |
| |
| class MyAction implements Action |
| |
| ]]> |
| </source> |
| |
| </section> |
| |
| |
| |
| <section name="Migrating file upload to Parts"> |
| |
| <p> |
| In turbine-4.0.1 and prior, file uploads were processed through the |
| data.getParameters().getFileItem("file_field_name") method and returned |
| a FileItem object. |
| </p> |
| |
| <p> |
| With Turbine-5.0, the framework is now using Java servlet 3.1.0. |
| As such, you will need to migrate this code using the |
| new Part object from the servlet spec. This actually saves you some |
| time since you don't have to convert the FileItem to a byte array and |
| then into an InputStream for processing.. you auto-magically get an |
| getInputStream() method on your javax.servlet.http.Part object to then |
| do as you please... |
| </p> |
| <source> |
| <![CDATA[ |
| |
| // all file items are now parts |
| Part fileItem = data.getParameters().getPart("file"); |
| if (fileItem != null) { |
| |
| InputStream is = fileItem.getInputStream(); |
| BufferedReader bfReader = null; |
| try { |
| bfReader = new BufferedReader(new InputStreamReader(is)); |
| String line = null; |
| while ((line = bfReader.readLine()) != null) { |
| |
| // do something with the input here ... |
| |
| } |
| } catch (IOException e) { |
| // handle exception here |
| e.printStackTrace(); |
| } finally { |
| try { |
| if (is != null) |
| is.close(); |
| } catch (Exception ex) { |
| // handle exception here |
| } |
| } |
| } |
| |
| ]]> |
| </source> |
| |
| <p> |
| And if you really do need a byte array (for example to store the |
| contents as a binary object in the database), you can do this using the |
| following method calls. |
| </p> |
| |
| <source> |
| <![CDATA[ |
| |
| InputStream is = fileItem.getInputStream(); |
| byte[] byteArray = IOUtils.toByteArray(is); |
| |
| ]]> |
| </source> |
| |
| </section> |
| |
| |
| <section name="Migrating to Quartz for Job Scheduling"> |
| |
| <p> |
| Quartz was introduced as a replacement for job scheduling starting |
| with Turbine 4.0. It provides Unix cron like abilities to manage |
| the automatic execution of tasks (or jobs) within your Turbine application. |
| </p> |
| |
| <p> |
| An example of a job might be periodic data or log cleanup that you |
| want to automate within the application itself. |
| </p> |
| |
| <subsection name="Creating a job"> |
| |
| <p> |
| Job creation has not really changed from the way jobs |
| were created in older versions of Turbine. You can refer |
| to the older documentation on how to create a job. For ease of |
| following the notes below however, we will add one simple job. |
| </p> |
| |
| <p> |
| Create the job class in com.myapp.modules.scheduledjobs.MyTurbineJob.java |
| </p> |
| |
| |
| <source> |
| <![CDATA[ |
| |
| package com.myapp.modules.scheduledjobs; |
| |
| import org.apache.commons.logging.Log; |
| import org.apache.commons.logging.LogFactory; |
| import org.apache.turbine.modules.ScheduledJob; |
| import org.apache.turbine.services.schedule.JobEntry; |
| import org.apache.turbine.services.security.SecurityService; |
| |
| public class MyTurbineJob extends ScheduledJob { |
| |
| /** Logging */ |
| private static Log log = LogFactory.getLog(MyTurbineJob.class); |
| |
| // Track the number of times the job has been run |
| private static int taskcount = 0; |
| |
| /** |
| * Constructor |
| */ |
| public MyTurbineJob() { |
| } |
| |
| @Override |
| public void run(JobEntry job) throws Exception { |
| |
| try { |
| |
| log.info("Job run: " + taskcount); |
| // do some interesting work to be scheduled here... |
| |
| } catch (Exception e) { |
| log.error("An error occurred running MyTurbineJob: " + e.toString()); |
| } |
| |
| taskcount++; |
| } |
| } |
| ]]> |
| </source> |
| |
| </subsection> |
| |
| <subsection name="Quartz service configuration"> |
| |
| <p> The Quartz scheduler is implemented as a Fulcrum component and needs |
| to be defined in the roleConfiguration.xml and componentConfiguration.xml |
| files in the WEB-INF/conf directory. |
| </p> |
| |
| <p> Modify the |
| <b>WEB-INF/conf/roleConfiguration.xml</b> |
| </p> |
| |
| <source> |
| <![CDATA[ |
| |
| |
| <role-list> |
| |
| ... |
| |
| <!-- Service required for the QuartzSchedulerService --> |
| <role |
| name="org.apache.fulcrum.quartz.QuartzScheduler" |
| shorthand="quartz" |
| default-class="org.apache.fulcrum.quartz.impl.QuartzSchedulerImpl" /> |
| |
| </role-list> |
| ]]> |
| </source> |
| |
| <p> Modify the |
| <b>WEB-INF/conf/componentConfiguration.xml</b> |
| </p> |
| |
| <source> |
| <![CDATA[ |
| |
| <componentConfig> |
| ... |
| |
| <quartz> |
| <configuration> |
| <properties> |
| <parameter name="org.quartz.scheduler.instanceName" value="TestScheduler"/> |
| <parameter name="org.quartz.scheduler.instanceId " value="AUTO"/> |
| <parameter name="org.quartz.scheduler.skipUpdateCheck" value="true"/> |
| <parameter name="org.quartz.threadPool.class" value="org.quartz.simpl.SimpleThreadPool"/> |
| <parameter name="org.quartz.threadPool.threadCount" value="3"/> |
| <parameter name="org.quartz.threadPool.threadPriority" value="5"/> |
| <parameter name="org.quartz.jobStore.misfireThreshold" value="60000"/> |
| <parameter name="org.quartz.jobStore.class" value="org.quartz.simpl.RAMJobStore"/> |
| <parameter name="org.quartz.plugin.jobInitializer.class" value="org.quartz.plugins.xml.XMLSchedulingDataProcessorPlugin"/> |
| <parameter name="org.quartz.plugin.jobInitializer.fileNames" value="../conf/quartz.xml"/> |
| <parameter name="org.quartz.plugin.jobInitializer.failOnFileNotFound" value="true"/> |
| <parameter name="org.quartz.plugin.jobInitializer.scanInterval" value="120"/> |
| <parameter name="org.quartz.plugin.jobInitializer.wrapInUserTransaction" value="false"/> |
| </properties> |
| </configuration> |
| </quartz> |
| |
| </componentConfig> |
| |
| ]]> |
| </source> |
| |
| <p> |
| Next, enable the Quartz scheduler service in the TurbineResources.properties file. |
| </p> |
| |
| |
| <source> |
| <![CDATA[ |
| services.SchedulerService.classname=org.apache.turbine.services.schedule.QuartzSchedulerService |
| ]]> |
| </source> |
| |
| <p> |
| Finally, we need the configuration file for Quartz itself to run the job. You can do this by creating a quartz.xml file in your WEB-INF/conf directory. |
| </p> |
| |
| <p> |
| |
| If you want to change the name, check the component configuration above |
| which defines the org.quartz.plugin.jobInitializer.fileNames value. |
| </p> |
| |
| <p> |
| This example quartz configuration is set to run our test job every 15 minutes. |
| </p> |
| |
| <source> |
| <![CDATA[ |
| <?xml version="1.0" encoding="utf-8"?> |
| <!-- Licensed to the Apache Software Foundation (ASF) under one or more contributor |
| license agreements. See the NOTICE file distributed with this work for additional |
| information regarding copyright ownership. The ASF licenses this file to |
| you under the Apache License, Version 2.0 (the "License"); you may not use |
| this file except in compliance with the License. You may obtain a copy of |
| the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required |
| by applicable law or agreed to in writing, software distributed under the |
| License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS |
| OF ANY KIND, either express or implied. See the License for the specific |
| language governing permissions and limitations under the License. --> |
| <job-scheduling-data |
| xmlns="http://www.quartz-scheduler.org/xml/JobSchedulingData" |
| xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" |
| xsi:schemaLocation="http://www.quartz-scheduler.org/xml/JobSchedulingData http://www.quartz-scheduler.org/xml/job_scheduling_data_2_0.xsd" |
| version="2.0"> |
| <pre-processing-commands> |
| <delete-jobs-in-group>*</delete-jobs-in-group> |
| <!-- clear all jobs in scheduler --> |
| <delete-triggers-in-group>*</delete-triggers-in-group> |
| <!-- clear all triggers in scheduler --> |
| </pre-processing-commands> |
| <processing-directives> |
| <!-- if there are any jobs/trigger in scheduler of same name (as in this |
| file), overwrite them --> |
| <overwrite-existing-data>true</overwrite-existing-data> |
| <!-- if there are any jobs/trigger in scheduler of same name (as in this |
| file), and over-write is false, ignore them rather then generating an error --> |
| <ignore-duplicates>false</ignore-duplicates> |
| </processing-directives> |
| <schedule> |
| <job> |
| <name>MyTurbineJob</name> |
| <group>TURBINE</group> |
| <description>Perform some task at a specified time</description> |
| <job-class>org.apache.turbine.services.schedule.JobEntryQuartz</job-class> |
| </job> |
| <trigger> |
| <simple> |
| <name>MyTurbineJobTrigger</name> |
| <group>TURBINE</group> |
| <job-name>MyTurbineJob</job-name> |
| <job-group>TURBINE</job-group> |
| <start-time>2018-06-01T00:00:00</start-time> |
| <misfire-instruction>MISFIRE_INSTRUCTION_RESCHEDULE_NOW_WITH_EXISTING_REPEAT_COUNT</misfire-instruction> |
| <repeat-count>-1</repeat-count> |
| <!-- check every 15 minutes --> |
| <repeat-interval>900000</repeat-interval> |
| </simple> |
| </trigger> |
| </schedule> |
| </job-scheduling-data> |
| |
| |
| ]]> |
| </source> |
| |
| </subsection> |
| |
| </section> |
| |
| </body> |
| </document> |