Quick start

This short tutorial is going to provide an example oh how to create a project including Sejda. We are going to create a simple command line utility which allows us to split an input document at page numbers specified by the user. This example can also be found in the Sejda scm here under the sejda-example module.

Set up the pom.xml

We are going to handle dependencies using Maven and we have to declare dependencies in our pom.xml. Our example project is going to use the SAMBox implementation of the split by page numbers task therefore we have to include sejda-core, sejda-model and sejda-sambox among our dependencies. We also want Sejda to perform validatation and we include Hibernate Validator.
The following is our resulting pom.xml which is configured as a module of the sejda project. When setting up your own project to use Sejda you will have to configure the pom to with your own groupId, artifactId etc.

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
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
                             http://maven.apache.org/maven-v4_0_0.xsd">
	<modelVersion>4.0.0</modelVersion>
	<description>Package containing examples on how to use Sejda.</description>
	<url>http://www.sejda.org</url>
	<parent>
		<groupId>org.sejda</groupId>
		<artifactId>sejda-parent</artifactId>
		<version>2.0.0.M1</version>
		<relativePath>../sejda-parent/pom.xml</relativePath>
	</parent>
 
	<artifactId>sejda-example</artifactId>
	<packaging>jar</packaging>
 
	<name>sejda example</name>
 
	<dependencies>
		<dependency>
			<groupId>org.sejda</groupId>
			<artifactId>sejda-core</artifactId>
			<version>${project.version}</version>
			<scope>compile</scope>
		</dependency>
		<dependency>
			<groupId>org.sejda</groupId>
			<artifactId>sejda-model</artifactId>
			<version>${project.version}</version>
			<scope>compile</scope>
		</dependency>
		<dependency>
			<groupId>org.sejda</groupId>
			<artifactId>sejda-sambox</artifactId>
			<version>${project.version}</version>
			<scope>compile</scope>
		</dependency>
		<dependency>
			<groupId>org.hibernate</groupId>
			<artifactId>hibernate-validator</artifactId>
			<version>4.2.0.Final</version>
			<scope>compile</scope>
		</dependency>
		<dependency>
			<groupId>ch.qos.logback</groupId>
			<artifactId>logback-classic</artifactId>
			<version>1.1.3</version>
			<scope>compile</scope>
		</dependency>
	</dependencies>
</project>

Configure Sejda

For each Sejda parameter class there is at least one corresponding task implementation capable of performing the manipulation requested by the parameters. In some case tasks are implemented using different underlying pdf manipulation libraries and Sejda needs to be configured to be instructed about what tasks we want to use.
We have to configure Sejda to use the SAMBox implementation of the split by page numbers task and to perform validation. To do that we include the file sejda.xml in our src/main/resources directory.

1
2
3
4
5
6
7
8
<sejda validation="true">
	<notification async="false" />
	<tasks>
		<task
			parameters="org.sejda.model.parameter.SplitByPagesParameters"
			task="org.sejda.impl.sambox.SplitByPageNumbersTask" />
	</tasks>
</sejda>

Java code

Our command line utility is going to accept four input arguments:

  1. -f to specify the input pdf document.
  2. -o to specify the output directory.
  3. -s in the form of a comma separated numbers to specify where we should split the document.
  4. -overwrite optional argument to specify if we want to overwrite existing files when writing the generated files.

Main skeleton

Our application skeleton consists in the following steps:

  1. validation of the number of arguments
  2. creation of the parameter instance
  3. registration of listeners
  4. execution of the split task
1
2
3
4
5
6
7
8
9
10
11
 public static void main(String[] args) throws NotificationContextException {
        if (args.length < 6) {
            printUsage();
            return;
        }
        SplitByPagesParameters params = createParameters(args);
        registerProgressListener();
        registerFailureListener();
        registerCompletedListener();
        executeTask(params);
    }

Validation of the number of arguments

We validate that the number of arguments is at least 6 otherwise we print a usage help using the printUsage method:

1
2
3
4
5
6
7
    private static void printUsage() {
        System.out.println("Usage: sejda-example -f /PATH_TO_INPUT/INPUT.pdf -o /OUTPUT_DIRECTORY -s n1,n2,n3.. -overwrite");
        System.out.println("Where /PATH_TO_INPUT/INPUT.pdf is the absolut path to the input pdf document.");
        System.out.println("Where /OUTPUT_DIRECTORY is the directory where output will be written.");
        System.out.println("Where n1,n2,n3.. is a comma separated list of page numbers where the document will be splitted at.");
        System.out.println("Where -overwrite is optional and instruct the utility to overwrite an existing file with the same name as the generated ones.");
    }

Creation of the parameter instance

We parse the input arguments creating and populating an instance of SplitByPagesParameters which is the expected parameter type.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
private static SplitByPagesParameters createParameters(String[] args) {
        SplitByPagesParameters params = new SplitByPagesParameters();
        for (int i = 0; i < args.length; i++) {
            if ("-f".equals(args[i])) {
                File inputFile = new File(args[++i]);
                params.setSource(PdfFileSource.newInstanceNoPassword(inputFile));
            } else if ("-o".equals(args[i])) {
                File outputDirectory = new File(args[++i]);
                params.setOutput(DirectoryOutput.newInstance(outputDirectory));
            } else if ("-s".equals(args[i])) {
                String[] pages = args[++i].split(",");
                for (int j = 0; j < pages.length; j++) {
                    params.addPage(Integer.valueOf(pages[j].trim()));
                }
            } else if ("-overwrite".equals(args[i])) {
                params.setOverwrite(true);
            }
        }
        return params;
    }

Registration of listeners

We are going define some listener to listen for events Sejda can notify.

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
    /**
     * Listener printing the percentage of work done by the task
     */
    private static class ProgressListener implements EventListener<PercentageOfWorkDoneChangedEvent> {
 
        public void onEvent(PercentageOfWorkDoneChangedEvent event) {
            System.out.println("Task progress: " + event.getPercentage().toPlainString() + "% done.");
        }
    }
 
    /**
     * Listener exiting with an error code in case of task failure
     */
    private static class FailureListener implements EventListener<TaskExecutionFailedEvent> {
 
        public void onEvent(TaskExecutionFailedEvent event) {
            System.err.println("Task execution failed.");
            // rethrow it to the main
            throw new SejdaRuntimeException(event.getFailingCause());
        }
    }
 
    /**
     * Listener informing the user about the task completion.
     */
    private static class CompletionListener implements EventListener<TaskExecutionCompletedEvent> {
 
        public void onEvent(TaskExecutionCompletedEvent event) {
            System.out.println("Task completed in " + event.getExecutionTime() + " millis.");
        }
    }

And we are going to register them to the Sejda global notification context. A thread local notification context is also supported and it provides notification in a “per thread” flavor.

1
2
3
4
5
6
7
8
9
10
11
    private static void registerProgressListener() throws NotificationContextException {
        GlobalNotificationContext.getContext().addListener(new ProgressListener());
    }
 
    private static void registerFailureListener() throws NotificationContextException {
        GlobalNotificationContext.getContext().addListener(new FailureListener());
    }
 
    private static void registerCompletedListener() throws NotificationContextException {
        GlobalNotificationContext.getContext().addListener(new CompletionListener());
    }

Execution of the split task

Finally we are going to execute our task using the parameters instance we just created:

1
2
3
    private static void executeTask(SplitByPagesParameters parameters) {
        new DefaultTaskExecutionService().execute(parameters);
    }

Summary

We just demonstrated how to create a simple project using Sejda covering some (but not all) the features Sejda provides. We have configured, created an populated a parameter instance, registered some listener and executed the task.
Source code is available in the Sejda scm repository.