:sources: ../../../../src/test/java/

== Implementing services

[[webservices]]
===  Webservices
A webservice is the suitable solution if your application needs to provide

* images, probably scaled and otherwise edited using an {appng}/org/appng/tools/image/ImageProcessor.html[ImageProcessor^]
* file attachments (aka downloads)
* custom formatted data as JSON, HTML, XML or any other required format

The interface to implement is {appng}/org/appng/api/Webservice.html[org.appng.api.Webservice^] or {appng}/org/appng/api/AttachmentWebservice.html[org.appng.api.AttachmentWebservice^].

Example:
[source,java]
----
@org.springframework.stereotype.Service
public class ImageService implements Webservice {

  public byte[] processRequest(Site site, Application application,
      Environment environment, Request request) throws BusinessException {
      Integer id = request.convert(request.getParameter("id"), Integer.class);
      Image image = getImage(id)
      return image.getData(id);
  }

  public String getContentType() {
    return "image/jpg";
  }

}
----

The URL schema for a webservice is

`http(s)://<host>[:<port>]/service/<site-name>/<application-name>/webservice/<service-name>`

Example: http://localhost:8080/service/manager/myapp/webservice/myWebservice


=== SOAP services
The interface {appng}/org/appng/api/SoapService.html[org.appng.api.SoapService^] is used to implement a https://en.wikipedia.org/wiki/SOAP[SOAP^] compliant service based on http://projects.spring.io/spring-ws/[Spring WS^]. For more information on Spring WS, see the https://docs.spring.io/spring-ws/site/reference/html/tutorial.html[Reference Documentation^] and this https://spring.io/guides/gs/producing-web-service/[Getting Started Guide^].

The following steps are required to build a SOAP service:

. Define a XSD schema
+
Because Spring WS uses the contract-first approach, it is essential to have an XSD schema defining the structure of the request and response elements. The schema file should be placed in `src/main/xsd`.
+
A minimalist XSD looks like this:
+
[source,xml]
----
<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" targetNamespace="http://example.com/soap"><!--1-->
	<xs:element name="exampleMethodRequest"><!--2-->
		<xs:complexType>
			<xs:sequence>
				<xs:element name="requestParam" type="xs:string" />
			</xs:sequence>
		</xs:complexType>
	</xs:element>
	<xs:element name="exampleMethodResponse"><!--2-->
		<xs:complexType>
			<xs:sequence>
				<xs:element name="responseParam" type="xs:string" />
			</xs:sequence>
		</xs:complexType>
	</xs:element>
</xs:schema>
----
<1> define the namespace for the schema
<2> define the request and response elements, following the naming convention `xyzRequest` and `xyzResponse`

. Generate JAXB classes for the schema file
+
The http://www.mojohaus.org/jaxb2-maven-plugin/Documentation/v2.2/[jaxb2-maven-plugin^] can be used to generate the Java classes using the https://docs.oracle.com/javase/8/docs/technotes/tools/unix/xjc.html[xjc^] binding compiler on this schema. The http://www.mojohaus.org/build-helper-maven-plugin/index.html[build-helper-maven-plugin^] is then used to add those classes to the project sources.
+
Example configuration from `pom.xml`:
+
[source,xml]
----
<build>
  <resources>
    <resource>
      <directory>src/main/xsd</directory><!--1-->
    </resource>
    <resource>
      <directory>src/main/resources</directory>
    </resource>
  </resources>
  <plugins>
    <plugin>
      <groupId>org.codehaus.mojo</groupId>
      <artifactId>jaxb2-maven-plugin</artifactId>
      <version>2.2</version>
      <executions>
        <execution>
          <id>generate</id>
          <goals>
            <goal>xjc</goal>
          </goals>
          <phase>generate-sources</phase>
          <configuration>
            <packageName>com.example.soap</packageName><!--2-->
          </configuration>
        </execution>
      </executions>
    </plugin>
    <plugin>
      <groupId>org.codehaus.mojo</groupId>
      <artifactId>build-helper-maven-plugin</artifactId>
      <version>1.12</version>
      <executions>
        <execution>
          <phase>generate-sources</phase>
          <goals>
            <goal>add-source</goal>
          </goals>
          <configuration>
            <sources>
              <source>target/generated-sources/jaxb</source><!--3-->
            </sources>
          </configuration>
        </execution>
      </executions>
    </plugin>
  </plugins>
</build>
----
<1> add `src/main/xsd` to the project's `resources`
<2> generate JAXB classes in the package `com.example.soap`
<3> add the folder with the generated JAXB classes as a source directory

. Implement the `SoapService`
+
[source,java]
----
import org.appng.api.Environment;
import org.appng.api.SoapService;
import org.appng.api.model.Application;
import org.appng.api.model.Site;
import org.springframework.ws.server.endpoint.annotation.Endpoint;
import org.springframework.ws.server.endpoint.annotation.PayloadRoot;
import org.springframework.ws.server.endpoint.annotation.RequestPayload;
import org.springframework.ws.server.endpoint.annotation.ResponsePayload;

import com.example.soap.ExampleMethodRequest;
import com.example.soap.ExampleMethodResponse;

@Endpoint //<1>
public class ExampleSoapService implements SoapService { //<2>

  private Site site;
  private Application application;
  private Environment environment;

  //<3>
  @PayloadRoot(namespace = "http://example.com/soap", localPart = "exampleMethodRequest")
  //<4>
  public @ResponsePayload ExampleMethodResponse getExample(
        @RequestPayload ExampleMethodRequest request) {
    ExampleMethodResponse exampleMethodResponse = new ExampleMethodResponse();
    exampleMethodResponse.setResponseParam(request.getRequestParam());
    return exampleMethodResponse;
  }

  //<5>
  public String getSchemaLocation() {
    return "example.xsd";
  }

  //<6>
  public String getContextPath() {
    return "com.example.soap";
  }

  // getters and setters here

}

----
<1> annotate with `@org.springframework.ws.server.endpoint.annotation.Endpoint`
<2> implement `org.appng.api.SoapService`
<3> define a `@PayloadRoot` that uses the `namespace` of the XSD schema and defining the `localPart`
<4> the method must use the a request-object as an `@RequestPayload` argument and response-object as an `@ResponsePayload` return type
<5> return the classpath-relative location of the schema file
<6> return the package name of the generated JAXB classes


The URL schema for the WSDL of the service is

`http(s)://<host>[:<port>]/service/<site-name>/<application-name>/soap/<service-name>/<service-name>.wsdl`

Example:
http://localhost:8080/service/manager/myapp/soap/exampleSoapService/exampleSoapService.wsdl


=== REST services
With appNG, you can easily create https://en.wikipedia.org/wiki/Representational_state_transfer[REST^]-based services by using the Spring framework's designated annotations. The most important ones to use here are {spring}/javadoc-api/org/springframework/web/bind/annotation/RestController.html[@RestController^],  {spring}/javadoc-api/org/springframework/web/bind/annotation/RequestMapping.html[@RequestMapping^] and {spring}/javadoc-api/org/springframework/web/bind/annotation/PathVariable.html[@PathVariable^].

Let's implement the add-operation of a simple `CalculatorService` as a `@RestController`.

[source,java]
----
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;

import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;

@RestController //<1>
public class CalculatorService {

    @RequestMapping(value = "/add/{a}/{b}", //<2>
        method = RequestMethod.GET, //<3>
        produces = MediaType.TEXT_PLAIN_VALUE) //<4>
	public ResponseEntity<Integer> add( //<5>
	        @PathVariable("a") Integer a, @PathVariable("b") Integer b) { //<6>
		return new ResponseEntity<Integer>(a + b, HttpStatus.OK); //<7>
	}
}
----
<1> Define the class ass  `@RestController`
<2> Define a `@RequestMapping` and the path it should match, using path variables
<3> Define the HTTP method
<4> Define the media-type this method produces
<5> Return a `ResponseEntity` of the desired type
<6> Map the path variables to the parameters
<7> Return the response

In order to make the necessary conversion of the `ResponseEntity` work, there needs to be an appropriate {spring}/javadoc-api/org/springframework/http/converter/HttpMessageConverter.html[HttpMessageConverter^] present in your application.


For the example above, this converter looks like this:

[source,java]
----
@Service
public class IntegerMessageConverter implements HttpMessageConverter<Integer> {

	public List<MediaType> getSupportedMediaTypes() {
		return Arrays.asList(MediaType.TEXT_PLAIN);
	}

	public boolean canWrite(Class<?> clazz, MediaType mediaType) {
		return Integer.class.equals(clazz);
	}

	public void write(Integer t, MediaType contentType, HttpOutputMessage outputMessage)
			throws IOException, HttpMessageNotWritableException {
		outputMessage.getBody().write(String.valueOf(t).getBytes());
	}

	public boolean canRead(Class<?> clazz, MediaType mediaType) {
		return false;
	}

	public Integer read(Class<? extends Integer> clazz, HttpInputMessage inputMessage)
			throws IOException, HttpMessageNotReadableException {
		return null;
	}

}
----


[TIP]
====
If your request-/response-types are JAXB-generated classes, you have to use a {spring}/javadoc-api/org/springframework/http/converter/xml/MarshallingHttpMessageConverter.html[MarshallingHttpMessageConverter^] instead.

For JSON-format, there's a {spring}/javadoc-api/org/springframework/http/converter/json/MappingJackson2HttpMessageConverter.html[MappingJackson2HttpMessageConverter^] available.
====

The URL schema for the REST service is

`http(s)://<host>[:<port>]/service/<site-name>/<application-name>/rest/path/to/service`

Example:
http://localhost:8080/service/manager/myapp/rest/add/3/4

==== Exception handling

For handling exceptions, you can (and should) use Spring's {spring}/javadoc-api/org/springframework/web/bind/annotation/ExceptionHandler.html[@ExceptionHandler^]. You may also use 
a bean annotated with {spring}/javadoc-api/org/springframework/web/bind/annotation/ControllerAdvice.html[@ControllerAdvice^] for centralized exception handling. More details can be found in the {spring}/spring-framework-reference/htmlsingle/#mvc-exceptionhandlers[corresponding section^] of Spring's reference documentation.

[TIP]
====
A method annotated with `@ExceptionHandler` can use a {appng}/org/appng/api/model/Site.html[Site^], {appng}/org/appng/api/model/Application.html[Application^] and {appng}/org/appng/api/Environment.html[Environment^] as a parameter.
====

==== JSON REST services
[source,java]
----
include::{sources}org/example/CalculatorService.java[indent=0]
----
<1> Map to the path `/add`
<2> Only allow the `POST` method
<3> Use constant from {spring}/javadoc-api/org/springframework/http/MediaType.html[MediaType^] to set the returned content type
<4> Use an `Operators` object as a parameter and annotate it with {spring}/javadoc-api/org/springframework/web/bind/annotation/RequestBody.html[RequestBody^].

[TIP]
====
A method annotated with `@RequestMapping` can use appNG's {appng}/org/appng/api/model/Site.html[Site^], {appng}/org/appng/api/model/Application.html[Application^] and {appng}/org/appng/api/Environment.html[Environment^] interfaces as a parameter.

Also note that there are many built-in {spring}/javadoc-api/org/springframework/web/method/support/HandlerMethodArgumentResolver.html[HandlerMethodArgumentResolver^]s that add support for additional parameter types.
====

To support JSON format, you have to register the aforementioned `MappingJackson2HttpMessageConverter` in your `beans.xml`:
[source,xml]
----
<bean class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter">
  <property name="prettyPrint" value="true" /> <!--1-->
</bean>
----
<1> Use  `prettyPrint` for a better readability.

The *request* will use the `POST` method and JSON formatting for it's content:
[source,json]
----
{
  "a" : 39,
  "b" : 3
}
----

The *response* to this request looks like this:
[source,json]
----
{
  "a" : 39,
  "b" : 3,
  "result" : 42
}
----

For more details on this topic, see {spring}/spring-framework-reference/htmlsingle/#mvc-ann-restcontroller[section 22.3.3^] of Spring's reference documentation.

===== Multipart requests
When using multipart requests (`enctype="multipart/form-data"`) in a `@RestController`, it is not possible to use a {spring}/javadoc-api/org/springframework/web/multipart/MultipartFile.html[MultipartFile^] as a parameter. The reason for that is the fact that appNG parses
the request by itself and wraps it in a {appng}/org/appng/forms/Request.html[org.appng.forms.Request^].

You can access this interal `org.appng.forms.Request` to retrieve the uploaded files as shown below (the `httpServletRequest` is a parameter of a RESTful method):
[source,java]
----
@PostMapping("/file-upload")
public ResponseEntity<String> handleFileUpload(HttpServletRequest httpServletRequest) {
    org.appng.forms.Request request = (org.appng.forms.Request)
        httpServletRequest.getAttribute(org.appng.forms.Request.REQUEST_PARSED);
    List<org.appng.forms.FormUpload> formUploads = request.getFormUploads("file");
  ...
}
----

As an alternative, you can just implement a {appng}/org/appng/api/Webservice.html[Webservice^] and use {appng}/org/appng/forms/RequestContainer.html#getFormUploads--[RequestContainer.getFormUploads()^] to retrieve the uploaded files.



=== Job scheduling
A {appng}/org/appng/api/ScheduledJob.html[org.appng.api.ScheduledJob^] is a (periodically or manually triggered) task that can be defined by an application. The implementation is simple:

[source,java]
----
import java.util.Map;

import org.appng.api.ScheduledJob;
import org.appng.api.model.Application;
import org.appng.api.model.Site;

public class DemoJob implements ScheduledJob {

	private String description;
	private Map<String, Object> jobDataMap;

	public void execute(Site site, Application application) throws Exception {
		// do something
	}

    // getters and setters here

}
----

With the `jobDataMap`, the required configuration parameters can be passed to the job. There are some predefined parameters for a job:

* `cronExpression` +
A https://en.wikipedia.org/wiki/Cron#CRON_expression[cron-expression^] describing when the job should be executed. The http://www.cronmaker.com/[Cronmaker^] is a useful tool helping you to build those expressions.
* `enabled` +
If set to `true` and the `cronExpression` property is properly set, the job will automatically be scheduled when the appNG platform starts.
* `runOnce` +
If set to `true`, this job will only run once per appNG cluster, i.e. it is not executed on each node, which is the default behavior.
* `hardInterruptable` +
If set to `true`, this job can safely be interrupted, e.g when a `Site` is being reloaded. This is achieved by running the job in a separate thread and calling {jse}/java/lang/Thread.html#interrupt--[Thread.interrupt^].
* `allowConcurrentExecutions` +
If set to `true`, multiple instances of this job can run concurrently (default is `false`).

The best way to configure a job is in `beans.xml`:
[source,xml]
----
<bean id="demoJob" class="com.myapp.job.Demojob">
  <property name="jobDataMap">
    <map>
      <entry key="enabled" value="true" />
      <entry key="runOnce" value="true" />
      <entry key="cronExpression" value="0 0 8 ? * *" /><!--1-->
      <entry key="foo" value="bar" /><!--2-->
      <entry key="answer" value="42" />
    </map>
  </property>
</bean>
----
<1> add the standard predefined parameters
<2> add some custom parameters

== Commonly used API

As you may have noticed, there are a handful of interfaces that occur quite often when implementing functionality with appNG:

* {appng}/org/appng/api/model/Site.html[org.appng.api.model.Site^]

* {appng}/org/appng/api/model/Application.html[org.appng.api.model.Application^]

* {appng}/org/appng/api/Request.html[org.appng.api.Request^]

* {appng}/org/appng/api/Environment.html[org.appng.api.Environment^]

* {appng}/org/appng/api/model/Properties.html[org.appng.api.model.Properties^]

The following section explains those in more detail.

=== `org.appng.api.model.Site`

A {appng}/org/appng/api/model/Site.html[Site^] first and foremost is used for aggregating several applications under a corporate domain. Most frequently, `site.getProperties()` is used to retrieve the site's
configuration in order to build some (relative or absolute) links, for example to a `WebService`:

The constants for the available property names can be found at {appng}/org/appng/api/SiteProperties.html[org.appng.api.SiteProperties^].

[source,java]
----
String servicePath = site.getProperties().getString(SiteProperties.SERVICE_PATH);
String absolutePath = String.format("%s/%s/%s/%s/webservice/pictureService?id=4711", site.getDomain(), servicePath, site.getName(), application.getName()));
----

Another common use-case for a site is to redirect the user to another location using `site.sendRedirect()`.


=== `org.appng.api.model.Application`
Through the {appng}/org/appng/api/model/Application.html[Application^] interface, any relevant information about the current application can be retrieved.
This includes

* {appng}/org/appng/api/model/Properties.html[Properties^] (`getProperties()`)
* {appng}/org/appng/api/model/Resources.html[Resources^] (`getResources()`)
* {appng}/org/appng/api/model/Permission.html[Permission^]s  (`getPermissions()`)
* {appng}/org/appng/api/model/Role.html[Role^]s  (`getRoles()`)
* {appng}/org/appng/api/model/ApplicationSubject.html[ApplicationSubject^]s  (`getApplicationSubjects()`)
* {appng}/org/appng/api/model/FeatureProvider.html[FeatureProvider^]  (`getFeatureProvider()`)

Please check the corresponding JavaDoc for details.

=== `org.appng.api.model.Request`
The {appng}/org/appng/api/Request.html[Request^] offers a large number of methods which serve one of the following purposes:

* retrieving request values (`getParameter()`, `getParameterList()`, `getParameterNames()`, `getParameters()`, `getParametersList()`, `getFormUploads()`)
* validating objects (`validateBean()`, `validateField()`)
* binding data (`fillBindObject()`, `setPropertyValue()`, `setPropertyValues()`)
* converting values (`canConvert()`, `convert()`)
* internationalization (`getMessage()`, `getMessageSource()`)
* retrieving information about the  environment (`getEnvironment()`, `getSubject()`, `getLocale()`)

Please check the corresponding JavaDoc for details.

=== `org.appng.api.Environment`

The {appng}/org/appng/api/Environment.html[Environment^] is used for storing and retrieving differently scoped attributes using `getAttribute(Scope scope, String name)` and
`setAttribute(Scope scope, String name, Object value)`.

Below you can find a description of the available {appng}/org/appng/api/Scope.html[org.appng.api.Scope^]s.

==== `PLATFORM` scope
This scope is mainly used for exchanging platform related configuration across different core components and is bound to
the {jee}/javax/servlet/ServletContext.html[javax.servlet.ServletContext^] appNG is executed in.
Therefore, this scope is only accessible from the appNG core and *privileged* applications.

The constants used as attributes names can be found at {appng}/org/appng/api/Platform.Environment.html[org.appng.api.Platform.Environment^].

Example usage:
[source,java]
----
Map<String, Site> siteMap = environment.getAttribute(Scope.PLATFORM, Platform.Environment.SITES);
----

WARNING: Even for privileged applications, the `PLATFORM` scope should be considered as 'read only', because it contains data that is critical for executing appNG correctly.

==== `SITE` scope
The `SITE` scope can be used to store and retrieve data that is *not* bound to a particular session and thus needs to be available on a more global level.
As the `PLATFORM` scope, it is bound to the {jee}/javax/servlet/ServletContext.html[javax.servlet.ServletContext^] appNG is executed in. There are no built-in attributes that
are stored in the `SITE` scope.


==== `SESSION` scope
This is propably the most commonly used scope when developing appNG applications. It is bound to the {jee}/javax/servlet/http/HttpSession.html[javax.servlet.http.HttpSession^] and
therefore keeps track of the user's session state. For example, you can use it to store the current workflow state within your application.

The built-in constants used as attribute names can be found at {appng}/org/appng/api/Session.html[org.appng.api.Session^].

Example usage:
[source,java]
----
String sessionId = environment.getAttribute(Scope.SESSION, Session.SID);
MyApplicationState state = environment.getAttribute(Scope.SESSION, "myApplicationState");
if ( null == state ) {
  state = new MyApplicationState();
  environment.setAttribute(Scope.SESSION, "myApplicationState", state);
}
----


==== `REQUEST` scope
The `REQUEST` scope is bound to the {jee}/javax/servlet/ServletRequest.html[javax.servlet.ServletRequest^] and therefore can be used to track the state of the request.
If, at all, you will most likely access this scope in a reading way.

The built-in constants used as attribute names can be found at
{appng}/org/appng/api/support/environment/EnvironmentKeys.html[org.appng.api.support.environment.EnvironmentKeys^]

Example usage:
[source,java]
----
Path path = environment.getAttribute(Scope.REQUEST, EnvironmentKeys.PATH_INFO);
String servletPath = environment.getAttribute(Scope.REQUEST, EnvironmentKeys.SERVLETPATH);
String queryString = environment.getAttribute(Scope.REQUEST, EnvironmentKeys.QUERY_STRING);
----


==== `URL` scope
The `URL` scope has solely the purpose of accessing URL parameters in a JSP with the <<appng-attribute,appNG:attribute>> tag.


=== `org.appng.api.model.Properties`
To configure an `Application` and a `Site`, both of these offer the `getProperties()`-method, returning some
{appng}/org/appng/api/model/Properties.html[org.appng.api.model.Properties^]. These can be used to retrieve type-safe configuration values, optionally providing a
default value.

[source,java]
----
Integer foo = properties.getInteger("foo");
Integer bar = properties.getInteger("bar", 42);
List<String> values = properties.getList("values", "foo;bar", ";");
----

You can also inject single property values into a bean using Spring's {spring}/javadoc-api/org/springframework/beans/factory/annotation/Value.html[@Value^] annotation:
[source,java]
----
@Value("${foo}")
private String foo;
private String servicePath;

public MyService(@Value("${site.service-path}") servicePath){
  this.servicePath = servicePath;
}

----
Be sure you've read the section about <<placeholders>>.



=== Sending emails
Using the classes contained in {appng}/org/appng/mail/package-summary.html[org.appng.mail^], it very is easy to send plain text and also HTML mails.
First, a `MailTransport` needs to be defined in `beans.xml`:

[source,xml]
----
<bean id="mailTransport" class="org.appng.mail.impl.DefaultTransport">
  <constructor-arg>
    <props>
      <prop key="mail.smtp.host">example.com</prop>
      <prop key="mail.smtp.port">25</prop>
      <prop key="mail.smtp.starttls.enable">true</prop>
      <prop key="mail.smtp.auth">true</prop>
    </props>
  </constructor-arg>
  <constructor-arg value="user" />
  <constructor-arg value="password" />
</bean>
----

This can than be used to send emails:
[source,java]
----
Mail mail = mailTransport.createMail();
mail.setFrom(mailSender);
mail.setSubject(mailSubject);
mail.addReceiver("johndoe@example.com", RecipientType.TO);
mail.addReceiver("janedoe@example.com", RecipientType.CC);
mail.setTextContent("Hello from appNG");
mail.setHTMLContent("Hello from <strong>appNG</strong>")
mailTransport.send(mail);
----

=== Working with images
Often applications are required to resize or crop images, hence appNG offers some tooling for that.

NOTE: Note that https://www.imagemagick.org[ImageMagick^] 6.9.9 needs to be installed and be available in the system's path (7.x is currently not supported).
Furthermore, the <<configurable-application-features,built-in application property>>  `featureImageProcessing` must be enabled.

The following example demonstrates how to fit an image into a (imaginary) box sized 120x120 pixel:
[source,java]
----
FeatureProvider featureProvider = application.getFeatureProvider(); //<1>
File imageCache = featureProvider.getImageCache(); //<2>
File sourceFile = new File(imageCache, "tempfile"); //<3>
byte[] pictureData = getPictureData(); //<4>
org.apache.commons.io.FileUtils.writeByteArrayToFile(sourceFile, pictureData); //<5>
ImageProcessor imageProcessor = featureProvider.getImageProcessor(sourceFile, "tempfile-resized"); //<6>
File result = imageProcessor.resize(120, 120).quality(0.8).getImage(); //<7>
----
<1> Retrieve a `FeatureProvider` from the `Application`.
<2> Retrieve a folder used for caching the image data.
<3> In that folder, create a new file.
<4> Retrieve the binary data of the image.
<5> Write the original image data to the `sourceFile`.
<6> Retrieve a new {appng}/org/appng/tools/image/ImageProcessor.html[ImageProcessor^] using `sourceFile` as a source and defining the name of the target file (which will be located in the folder `imageCache`).
<7> Resize the image to make it fit into a (imaginary) box with a size of 120x120 pixel (aspect ratio is kept!), set the quality to 80%, and finally return the target file.
