├── .gitignore
├── README.md
├── pom.xml
└── src
├── config
└── checkstyle.xml
├── main
├── java
│ └── com
│ │ └── github
│ │ └── jarlakxen
│ │ └── embedphantomjs
│ │ ├── ExecutionTimeout.java
│ │ ├── PhantomJSReference.java
│ │ ├── Version.java
│ │ ├── exception
│ │ └── UnexpectedProcessEndException.java
│ │ └── executor
│ │ ├── PhantomJSConsoleExecutor.java
│ │ └── PhantomJSFileExecutor.java
└── resources
│ ├── etc
│ └── license.txt
│ └── phantomjs
│ └── data.properties
└── test
└── java
└── com
└── github
└── jarlakxen
└── embedphantomjs
└── PhantomJSExecutorTest.java
/.gitignore:
--------------------------------------------------------------------------------
1 | .classpath
2 | .project
3 |
4 | *.class
5 |
6 | .settings/
7 | target/
8 |
9 | # Package Files #
10 | *.jar
11 | *.war
12 | *.ear
13 |
14 | #pom
15 | release.properties
16 | pom.xml.releaseBackup
17 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | embedphantomjs
2 | ==============
3 |
4 | Embedded PhantomJS for Java
5 |
6 | This project provides an easy interface for execute PhantomJS with Java.
7 |
8 | ## Why?
9 |
10 | - Easy way to execute JS inside Java
11 | - Easy way to make a Scraper with Java
12 |
13 | ### Maven
14 |
15 | Stable [OSS Sonatype](https://oss.sonatype.org/content/repositories/releases/com/github/jarlakxen/embedphantomjs/maven-metadata.xml)
16 |
17 | ```xml
18 |
19 | com.github.jarlakxen
20 | embedphantomjs
21 | 3.0
22 |
23 | ```
24 | ### Changelog
25 |
26 | - 3.0
27 | - Move to Java 8
28 | - Remove Guava dependancy, switch to `CompletableFuture`
29 |
30 | - 2.9
31 | - https://github.com/Jarlakxen/embedphantomjs/pull/3
32 | - Update dependancies
33 | - Sopport for versions last versions of PhantomJS
34 | - Move PhantomJS download url to bitbucket.
35 |
36 | - 2.8
37 | - Better windows support ( Thanks to @Dmitry-Shweikus )
38 |
39 | - 2.7
40 | - Unify Sync and Async interfaces for PhantomJSFileExecutor
41 | - Improve error handling
42 |
43 | - 2.6
44 | - Some API improvments in PhantomJSFileExecutor
45 | - Improve the core of the PhantomJSConsoleExecutor
46 |
47 | - 2.5
48 | - Some API improvments
49 |
50 | - 2.4
51 | - Provide some basic information of the PhantomJS process
52 | - Better exception handling
53 |
54 | - 2.3
55 | - Bug fixing
56 |
57 | - 2.2
58 | - Mejor API Refactor
59 | - Now supports console style executor
60 |
61 | - 2.1
62 | - Add asyncronic execution
63 |
64 | - 2.0
65 | - Sopport for versions 1.9.2, 1.9.1, 1.9.0, 1.8.2, 1.8.1, 1.8.0
66 | - Sopport binary versioned
67 |
68 | - 1.3
69 | - Full support for input stream script
70 |
71 | - 1.2
72 | - Bug fixing
73 |
74 | - 1.1
75 | - Bug fixing
76 |
77 | - 1.0
78 | - Auto-detect OS
79 | - Auto-detect architecture
80 | - Sopport for versions 1.7.0, 1.6.1, 1.6.0, 1.5.0, 1.4.1, 1.4.0, 1.3.0
81 | - Check native installation
82 | - Download from page
83 |
84 |
85 |
86 | ### Supported Versions
87 |
88 | Versions: 2.1.1, 1.9.8, 1.9.7, 1.9.6, 1.9.5, 1.9.4, 1.9.3, 1.9.2, 1.9.1, 1.9.0, 1.8.2, 1.8.1, 1.8.0, 1.7.0, 1.6.1, 1.6.0, 1.5.0, 1.4.1, 1.4.0, 1.3.0
89 | Support for Linux, Windows and MacOSX.
90 |
91 | ### Usage
92 |
93 | ####Example I:
94 |
95 | PhantomJSFileExecutor ex = new PhantomJSFileExecutor(PhantomJSReference.create().build(), new ExecutionTimeout(1, TimeUnit.SECONDS));
96 | String output = executor.execute(new File("~/scrapper.js")).get();
97 | System.out.println(output); // This prints "TEST1"
98 |
99 |
100 | ####Example II:
101 |
102 | PhantomJSFileExecutor ex = new new PhantomJSFileExecutor(PhantomJSReference.create().build(), new ExecutionTimeout(1, TimeUnit.SECONDS));
103 | String output = executor.execute("console.log('TEST1');phantom.exit();").get()
104 | System.out.println(output); // This prints "TEST1"
105 |
106 | ####Example III:
107 |
108 | PhantomJSConsoleExecutor ex = new PhantomJSConsoleExecutor(PhantomJSReference.create().build());
109 | ex.start();
110 | ex.execute("var system = require('system');");
111 | System.out.println(ex.execute("system.stdout.writeLine('TEST1');", "true")); // This prints "TEST1"
112 | System.out.println( ex.execute("system.stdout.writeLine('TEST2');", "true")); // This prints "TEST2"
113 | ex.destroy();
114 |
115 | [](https://bitdeli.com/free "Bitdeli Badge")
116 |
--------------------------------------------------------------------------------
/pom.xml:
--------------------------------------------------------------------------------
1 |
2 | 4.0.0
3 | com.github.jarlakxen
4 | embedphantomjs
5 | 3.1-SNAPSHOT
6 | EmbedPhantomJS
7 |
8 | Embedded PhantomJS for Java
9 | https://github.com/Jarlakxen/embedphantomjs
10 |
11 |
12 |
13 | The Apache Software License, Version 2.0
14 | http://www.apache.org/licenses/LICENSE-2.0.txt
15 | repo
16 |
17 |
18 |
19 |
20 | scm:git:git@github.com:Jarlakxen/embedphantomjs.git
21 | scm:git:git@github.com:Jarlakxen/embedphantomjs.git
22 | git@github.com:Jarlakxen/embedphantomjs.git
23 | HEAD
24 |
25 |
26 |
27 |
28 | jarlakxen
29 | Facundo Viale
30 | fviale@despegar.com
31 | GMT+3
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 | sonatype-nexus-snapshots
40 | Sonatype Nexus Snapshots
41 | https://oss.sonatype.org/content/repositories/snapshots/
42 |
43 |
44 | sonatype-nexus-staging
45 | Nexus Release Repository
46 | https://oss.sonatype.org/service/local/staging/deploy/maven2/
47 |
48 |
49 |
50 |
51 |
52 | org.apache.commons
53 | commons-lang3
54 | 3.4
55 |
56 |
57 | commons-io
58 | commons-io
59 | 2.5
60 |
61 |
62 | org.apache.commons
63 | commons-compress
64 | 1.12
65 |
66 |
67 |
68 | org.slf4j
69 | log4j-over-slf4j
70 | 1.7.21
71 |
72 |
73 |
74 | junit
75 | junit
76 | 4.12
77 | test
78 |
79 |
80 |
81 |
82 |
83 |
84 | org.apache.maven.plugins
85 | maven-compiler-plugin
86 | 3.5.1
87 |
88 | 1.8
89 | 1.8
90 | UTF-8
91 |
92 |
93 |
94 |
95 | org.apache.maven.plugins
96 | maven-release-plugin
97 | 2.5.3
98 |
99 |
100 |
101 | org.apache.maven.plugins
102 | maven-resources-plugin
103 | 2.5
104 |
105 | UTF-8
106 |
107 |
108 |
109 |
110 | org.apache.maven.plugins
111 | maven-source-plugin
112 | 3.0.1
113 |
114 |
115 | attach-sources
116 |
117 | jar-no-fork
118 |
119 |
120 |
121 |
122 |
123 |
124 | org.apache.maven.plugins
125 | maven-javadoc-plugin
126 | 2.10.4
127 |
128 |
129 | attach-javadocs
130 |
131 | jar
132 |
133 |
134 |
135 |
136 |
137 |
138 | org.apache.maven.plugins
139 | maven-surefire-plugin
140 | 2.11
141 |
142 |
143 | **/examples/**
144 |
145 |
146 |
147 |
148 |
149 | com.mycila.maven-license-plugin
150 | maven-license-plugin
151 | 1.9.0
152 |
153 | ${basedir}/src/main/resources/etc/license.txt
154 | false
155 | true
156 | true
157 | true
158 |
159 | src/**/*.java
160 | **/test/**/*.java
161 |
162 |
163 | 2013
164 | Facundo Viale
165 | Facundo Viale (Jarlakxen@github)
166 |
167 | UTF-8
168 |
169 |
170 |
171 |
172 | org.apache.maven.plugins
173 | maven-checkstyle-plugin
174 | 2.9.1
175 |
176 | config/checkstyle.xml
177 |
178 | ${basedir}/src/test/**/*
179 |
180 |
181 |
182 |
183 |
184 | org.apache.maven.plugins
185 | maven-gpg-plugin
186 | 1.6
187 |
188 | ${gpg.passphrase}
189 |
190 |
191 |
192 | sign-artifacts
193 | verify
194 |
195 | sign
196 |
197 |
198 |
199 |
200 |
201 |
202 | org.sonatype.plugins
203 | nexus-staging-maven-plugin
204 | 1.6.7
205 | true
206 |
207 | ossrh
208 | https://oss.sonatype.org/
209 | true
210 |
211 |
212 |
213 |
214 |
215 |
216 |
217 | release-sign-artifacts
218 |
219 |
220 | performRelease
221 | true
222 |
223 |
224 |
225 |
226 | include-sources
227 |
228 |
229 |
230 | /
231 | true
232 | src/main/java
233 |
234 | **/*.java
235 |
236 |
237 |
238 |
239 |
240 |
241 |
242 |
243 |
--------------------------------------------------------------------------------
/src/config/checkstyle.xml:
--------------------------------------------------------------------------------
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 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 |
--------------------------------------------------------------------------------
/src/main/java/com/github/jarlakxen/embedphantomjs/ExecutionTimeout.java:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright (C) 2013
3 | * Facundo Viale
4 | *
5 | * with contributions from
6 | * Facundo Viale (Jarlakxen@github)
7 | *
8 | * Licensed under the Apache License, Version 2.0 (the "License");
9 | * you may not use this file except in compliance with the License.
10 | * You may obtain a copy of the License at
11 | *
12 | * http://www.apache.org/licenses/LICENSE-2.0
13 | *
14 | * Unless required by applicable law or agreed to in writing, software
15 | * distributed under the License is distributed on an "AS IS" BASIS,
16 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17 | * See the License for the specific language governing permissions and
18 | * limitations under the License.
19 | */
20 | package com.github.jarlakxen.embedphantomjs;
21 |
22 | import java.util.concurrent.TimeUnit;
23 |
24 | public class ExecutionTimeout {
25 |
26 | private final long timeout;
27 | private final TimeUnit unit;
28 |
29 | public ExecutionTimeout(long timeout, TimeUnit unit) {
30 | this.timeout = timeout;
31 | this.unit = unit;
32 | }
33 |
34 | public long getTimeout() {
35 | return timeout;
36 | }
37 |
38 | public TimeUnit getUnit() {
39 | return unit;
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/src/main/java/com/github/jarlakxen/embedphantomjs/PhantomJSReference.java:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright (C) 2013
3 | * Facundo Viale
4 | *
5 | * with contributions from
6 | * Facundo Viale (Jarlakxen@github)
7 | *
8 | * Licensed under the Apache License, Version 2.0 (the "License");
9 | * you may not use this file except in compliance with the License.
10 | * You may obtain a copy of the License at
11 | *
12 | * http://www.apache.org/licenses/LICENSE-2.0
13 | *
14 | * Unless required by applicable law or agreed to in writing, software
15 | * distributed under the License is distributed on an "AS IS" BASIS,
16 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17 | * See the License for the specific language governing permissions and
18 | * limitations under the License.
19 | */
20 | package com.github.jarlakxen.embedphantomjs;
21 |
22 | import java.io.File;
23 | import java.io.FileInputStream;
24 | import java.io.FileOutputStream;
25 | import java.io.IOException;
26 | import java.net.URL;
27 | import java.nio.charset.Charset;
28 | import java.util.Properties;
29 | import org.apache.commons.compress.archivers.ArchiveEntry;
30 | import org.apache.commons.compress.archivers.ArchiveInputStream;
31 | import org.apache.commons.compress.archivers.tar.TarArchiveInputStream;
32 | import org.apache.commons.compress.archivers.zip.ZipArchiveInputStream;
33 | import org.apache.commons.compress.compressors.bzip2.BZip2CompressorInputStream;
34 | import org.apache.commons.compress.compressors.gzip.GzipCompressorInputStream;
35 | import org.apache.commons.io.FileUtils;
36 | import org.apache.commons.io.IOUtils;
37 | import org.apache.commons.lang3.StringUtils;
38 | import org.apache.commons.lang3.builder.ToStringBuilder;
39 | import org.apache.log4j.Logger;
40 |
41 | public class PhantomJSReference {
42 |
43 | private static final Logger LOGGER = Logger.getLogger(PhantomJSReference.class);
44 |
45 | public static final String PHANTOMJS_NATIVE_CMD = "/usr/bin/phantomjs";
46 |
47 | public static final String PHANTOMJS_DATA_FILE = "phantomjs/data.properties";
48 |
49 | public static final String PHANTOMJS_DOWNLOAD_BINARY_PATH = "/bin/phantomjs";
50 |
51 | public static PhantomJSReferenceBuilder create() {
52 | return new PhantomJSReferenceBuilder();
53 | }
54 |
55 | /***
56 | * This inner builder is defined because we want immutable BusinessDomain
57 | * object. Ref. Effective Java Second Edition Pag. 14.
58 | *
59 | */
60 | public static class PhantomJSReferenceBuilder {
61 | private Version version = Version.v_2_1_1;
62 | private String architecture = System.getProperty("os.arch").toLowerCase();
63 | private String hostOs;
64 |
65 | private String downloadUrl = "https://bitbucket.org/ariya/phantomjs/downloads/";
66 | private String targetInstallationFolder = System.getProperty("user.home") + "/.embedphantomjs";
67 |
68 | private String commandLineOptions;
69 |
70 | public PhantomJSReferenceBuilder withVersion(final Version version) {
71 | this.version = version;
72 | return this;
73 | }
74 |
75 | public PhantomJSReferenceBuilder withArchitecture(final String architecture) {
76 | this.architecture = architecture;
77 | return this;
78 | }
79 |
80 | public PhantomJSReferenceBuilder withHostOS(final String hostOs) {
81 | this.hostOs = hostOs;
82 | return this;
83 | }
84 |
85 | public PhantomJSReferenceBuilder useDownloadUrl(final String downloadUrl) {
86 | this.downloadUrl = downloadUrl;
87 | return this;
88 | }
89 | /**
90 | * Adds command line options so they are sent to PhantomJs by the executor
91 | * @param commandLineOptions Array of command line options to send
92 | * @return Reference to the builder
93 | */
94 | public PhantomJSReferenceBuilder addCommandLineOptions(final String... commandLineOptions){
95 | this.commandLineOptions = StringUtils.join(commandLineOptions, " ");
96 | return this;
97 | }
98 | public PhantomJSReferenceBuilder useTargetInstallationFolder(final String targetInstallationFolder) {
99 | this.targetInstallationFolder = targetInstallationFolder;
100 | return this;
101 | }
102 |
103 | public PhantomJSReference build() {
104 | return new PhantomJSReference(this);
105 | }
106 |
107 |
108 | public PhantomJSReferenceBuilder()
109 | {
110 | final String os = System.getProperty("os.name").toLowerCase();
111 | if (os.contains("win"))
112 | hostOs = "win";
113 | else if (os.contains("mac"))
114 | hostOs = "macosx";
115 | else
116 | hostOs = "linux";
117 | }
118 | }
119 |
120 | private Version version;
121 | private String architecture;
122 | private String hostOs;
123 | private String downloadUrl;
124 | private String targetInstallationFolder;
125 | private String binaryPath;
126 | private String commandLineOptions;
127 |
128 | private PhantomJSReference(final PhantomJSReferenceBuilder builder) {
129 | this.version = builder.version;
130 | this.architecture = builder.architecture;
131 | this.hostOs = builder.hostOs;
132 | this.downloadUrl = builder.downloadUrl;
133 | this.targetInstallationFolder = builder.targetInstallationFolder;
134 | this.commandLineOptions = builder.commandLineOptions ==null?"":builder.commandLineOptions;
135 | }
136 |
137 | public String getBinaryPath() {
138 | if (binaryPath == null) {
139 | ensureBinary();
140 | }
141 | return binaryPath;
142 | }
143 |
144 | public synchronized void ensureBinary() {
145 |
146 | if (binaryPath != null) {
147 | // The binary is already ensure
148 | return;
149 | }
150 |
151 | // Check if phantomjs is installed locally
152 | if (Version.NATIVE.equals(version)) {
153 |
154 | LOGGER.debug("Checking PhantomJS native installation");
155 | if (this.checkPhantomJSBinaryAnyVersion(PHANTOMJS_NATIVE_CMD)) {
156 | LOGGER.debug("Native installation founded");
157 | binaryPath = PHANTOMJS_NATIVE_CMD;
158 | return;
159 | } else {
160 | throw new RuntimeException("Invalid native installation!");
161 | }
162 | }
163 |
164 | if (!getVersion().isDownloadSopported()) {
165 | throw new RuntimeException("Unsopported version for downloading!");
166 | }
167 |
168 | final File binaryFile = new File(this.getTargetInstallationFolder() + "/" + this.getVersion().getDescription() + "/phantomjs");
169 | final String binaryFilePath = binaryFile.getAbsolutePath();
170 |
171 | // Check if phantomjs is already installed in target path
172 | LOGGER.debug("Checking PhantomJS installation in " + binaryFilePath);
173 | if (this.checkPhantomJSBinaryVersion(binaryFilePath, getVersion())) {
174 | LOGGER.debug("PhantomJS founded in " + binaryFilePath);
175 | binaryPath = binaryFilePath;
176 | } else {
177 | LOGGER.debug("PhantomJS not founded in " + binaryFilePath);
178 |
179 | try {
180 | downloadPhantomJS(binaryFile);
181 | } catch (IOException e) {
182 | throw new RuntimeException(e);
183 | }
184 |
185 | if (!this.checkPhantomJSBinaryVersion(binaryFilePath, getVersion())) {
186 | throw new RuntimeException("Invalid download");
187 | }
188 |
189 | binaryPath = binaryFilePath;
190 | }
191 | }
192 | /**
193 | * Command line options that are going to be sent to PhantomJS
194 | * @return
195 | */
196 | public String getCommandLineOptions() {
197 | return commandLineOptions;
198 | }
199 |
200 | private void downloadPhantomJS(final File binaryFile) throws IOException {
201 | final Properties properties = new Properties();
202 | properties.load(this.getClass().getClassLoader().getResourceAsStream(PHANTOMJS_DATA_FILE));
203 |
204 | String name = properties.getProperty(this.getVersion().getDescription() + "." + this.getHostOs() + ".name");
205 |
206 | final String architecture = this.getArchitecture().indexOf("64") >= 0 ? "x86_64" : "i686";
207 |
208 | LOGGER.debug("System Data: Arch [" + architecture + "] - OS [" + this.getHostOs() + "]");
209 |
210 | if (this.getHostOs().equals("linux")) {
211 | name = String.format(name, architecture);
212 | }
213 |
214 | // Download PhantomJS
215 | final URL downloadPath = new URL(this.getDownloadUrl() + name);
216 | final File phantomJsCompressedFile = new File(System.getProperty("java.io.tmpdir") + "/" + name);
217 |
218 | LOGGER.info("Downloading " + downloadPath.getPath() + " ...");
219 |
220 | FileUtils.copyURLToFile(downloadPath, phantomJsCompressedFile);
221 |
222 | ArchiveInputStream archiveInputStream = null;
223 |
224 | if (phantomJsCompressedFile.getName().endsWith(".zip")) {
225 |
226 | archiveInputStream = new ZipArchiveInputStream(new FileInputStream(phantomJsCompressedFile));
227 |
228 | } else if (phantomJsCompressedFile.getName().endsWith(".bz2")) {
229 |
230 | archiveInputStream = new TarArchiveInputStream(new BZip2CompressorInputStream(new FileInputStream(phantomJsCompressedFile)));
231 |
232 | } else if (phantomJsCompressedFile.getName().endsWith(".gz")) {
233 |
234 | archiveInputStream = new TarArchiveInputStream(new GzipCompressorInputStream(new FileInputStream(phantomJsCompressedFile)));
235 |
236 | }
237 |
238 | ArchiveEntry entry;
239 | while ((entry = archiveInputStream.getNextEntry()) != null) {
240 | if (entry.getName().endsWith(PHANTOMJS_DOWNLOAD_BINARY_PATH) || entry.getName().toLowerCase().endsWith("phantomjs.exe")) {
241 |
242 | // Create target folder
243 | new File(this.getTargetInstallationFolder() + "/" + this.getVersion().getDescription()).mkdirs();
244 |
245 | FileUtils.forceMkdir(new File(binaryFile.getParent()));
246 |
247 | if (!binaryFile.exists()) {
248 | binaryFile.createNewFile();
249 | }
250 |
251 | binaryFile.setExecutable(true);
252 | binaryFile.setReadable(true);
253 |
254 | // Untar the binary file
255 | final FileOutputStream outputBinary = new FileOutputStream(binaryFile);
256 |
257 | LOGGER.info("Un-compress download to " + downloadPath.getPath() + " ...");
258 | IOUtils.copy(archiveInputStream, outputBinary);
259 |
260 | outputBinary.close();
261 | }
262 | }
263 |
264 | archiveInputStream.close();
265 | }
266 |
267 | private String checkPhantomJSBinary(final String path) {
268 | try {
269 | final Process process = Runtime.getRuntime().exec(path + " --version");
270 | process.waitFor();
271 |
272 | final String processOutput = IOUtils.toString(process.getInputStream(), Charset.defaultCharset());
273 |
274 | return processOutput.substring(0, 5);
275 |
276 | } catch (Exception e) {
277 | LOGGER.warn(e);
278 | }
279 |
280 | return null;
281 | }
282 |
283 | private Boolean checkPhantomJSBinaryAnyVersion(final String path) {
284 | final String outputVersion = checkPhantomJSBinary(path);
285 | return Version.fromValue(outputVersion) != null;
286 | }
287 |
288 | private Boolean checkPhantomJSBinaryVersion(final String path, final Version version) {
289 | final String outputVersion = checkPhantomJSBinary(path);
290 | return version.getDescription().equals(outputVersion);
291 | }
292 |
293 | public Version getVersion() {
294 | return this.version;
295 | }
296 |
297 | public String getHostOs() {
298 | return this.hostOs;
299 | }
300 |
301 | public String getArchitecture() {
302 | return this.architecture;
303 | }
304 |
305 | public String getDownloadUrl() {
306 | return this.downloadUrl;
307 | }
308 |
309 | public String getTargetInstallationFolder() {
310 | return this.targetInstallationFolder;
311 | }
312 |
313 | @Override
314 | public String toString() {
315 | return ToStringBuilder.reflectionToString(this);
316 | }
317 | }
318 |
--------------------------------------------------------------------------------
/src/main/java/com/github/jarlakxen/embedphantomjs/Version.java:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright (C) 2013
3 | * Facundo Viale
4 | *
5 | * with contributions from
6 | * Facundo Viale (Jarlakxen@github)
7 | *
8 | * Licensed under the Apache License, Version 2.0 (the "License");
9 | * you may not use this file except in compliance with the License.
10 | * You may obtain a copy of the License at
11 | *
12 | * http://www.apache.org/licenses/LICENSE-2.0
13 | *
14 | * Unless required by applicable law or agreed to in writing, software
15 | * distributed under the License is distributed on an "AS IS" BASIS,
16 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17 | * See the License for the specific language governing permissions and
18 | * limitations under the License.
19 | */
20 | package com.github.jarlakxen.embedphantomjs;
21 |
22 | public enum Version {
23 | v_2_1_1("2.1.1", true), v_1_9_8("1.9.8", true), v_1_9_7("1.9.7", true),
24 | v_1_9_6("1.9.6", true), v_1_9_5("1.9.5", true), v_1_9_4("1.9.4", true), v_1_9_3("1.9.3", true),
25 | v_1_9_2("1.9.2", true), v_1_9_1("1.9.1", true), v_1_9_0("1.9.0", true), v_1_8_2("1.8.2", true),
26 | v_1_8_1("1.8.1", true), v_1_8_0("1.8.0", true), v_1_7_0("1.7.0", true), v_1_6_1("1.6.1", true),
27 | v_1_6_0("1.6.0", true), v_1_5_0("1.5.0", true), v_1_4_1("1.4.1", true), v_1_4_0("1.4.0", false),
28 | v_1_3_0("1.3.0", false), NATIVE(null, false);
29 |
30 | public static Version fromValue(final String version) {
31 |
32 | for (Version value : Version.values()) {
33 | if (value.getDescription().equals(version)) {
34 | return value;
35 | }
36 | }
37 |
38 | return null;
39 | }
40 |
41 | private final String description;
42 | private final boolean downloadSopported;
43 |
44 | private Version(final String description, final boolean downloadSopported) {
45 | this.description = description;
46 | this.downloadSopported = downloadSopported;
47 | }
48 |
49 | public String getDescription() {
50 | return this.description;
51 | }
52 |
53 | public boolean isDownloadSopported() {
54 | return this.downloadSopported;
55 | }
56 |
57 | @Override
58 | public String toString() {
59 | return this.getDescription();
60 | }
61 |
62 | }
63 |
--------------------------------------------------------------------------------
/src/main/java/com/github/jarlakxen/embedphantomjs/exception/UnexpectedProcessEndException.java:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright (C) 2013
3 | * Facundo Viale
4 | *
5 | * with contributions from
6 | * Facundo Viale (Jarlakxen@github)
7 | *
8 | * Licensed under the Apache License, Version 2.0 (the "License");
9 | * you may not use this file except in compliance with the License.
10 | * You may obtain a copy of the License at
11 | *
12 | * http://www.apache.org/licenses/LICENSE-2.0
13 | *
14 | * Unless required by applicable law or agreed to in writing, software
15 | * distributed under the License is distributed on an "AS IS" BASIS,
16 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17 | * See the License for the specific language governing permissions and
18 | * limitations under the License.
19 | */
20 | package com.github.jarlakxen.embedphantomjs.exception;
21 |
22 | public class UnexpectedProcessEndException extends RuntimeException {
23 | private static final long serialVersionUID = 6312464814429570001L;
24 |
25 | public UnexpectedProcessEndException() {
26 |
27 | }
28 |
29 | public UnexpectedProcessEndException(final Throwable throwable) {
30 | super(throwable);
31 | }
32 |
33 | }
34 |
--------------------------------------------------------------------------------
/src/main/java/com/github/jarlakxen/embedphantomjs/executor/PhantomJSConsoleExecutor.java:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright (C) 2013
3 | * Facundo Viale
4 | *
5 | * with contributions from
6 | * Facundo Viale (Jarlakxen@github)
7 | *
8 | * Licensed under the Apache License, Version 2.0 (the "License");
9 | * you may not use this file except in compliance with the License.
10 | * You may obtain a copy of the License at
11 | *
12 | * http://www.apache.org/licenses/LICENSE-2.0
13 | *
14 | * Unless required by applicable law or agreed to in writing, software
15 | * distributed under the License is distributed on an "AS IS" BASIS,
16 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17 | * See the License for the specific language governing permissions and
18 | * limitations under the License.
19 | */
20 | package com.github.jarlakxen.embedphantomjs.executor;
21 |
22 | import static java.util.Arrays.*;
23 |
24 | import java.io.BufferedReader;
25 | import java.io.File;
26 | import java.io.IOException;
27 | import java.io.InputStream;
28 | import java.io.InputStreamReader;
29 | import java.io.OutputStream;
30 | import java.lang.reflect.Field;
31 | import java.nio.charset.Charset;
32 | import java.util.List;
33 | import java.util.concurrent.CompletableFuture;
34 | import java.util.concurrent.ExecutorService;
35 | import java.util.concurrent.Executors;
36 |
37 | import org.apache.commons.io.IOUtils;
38 | import org.apache.commons.lang3.StringUtils;
39 | import org.apache.log4j.Logger;
40 |
41 | import com.github.jarlakxen.embedphantomjs.PhantomJSReference;
42 | import com.github.jarlakxen.embedphantomjs.exception.UnexpectedProcessEndException;
43 |
44 | public class PhantomJSConsoleExecutor {
45 |
46 | private static final Logger LOGGER = Logger.getLogger(PhantomJSConsoleExecutor.class);
47 |
48 | private static final int DEFAULT_BUFFER_SIZE = 1024 * 4;
49 | private static final int EOF = -1;
50 |
51 | private static final char SYSTEM_NEWLINE[] = System.getProperty("line.separator").toCharArray();
52 |
53 | private static final String DEFAULT_PHANTOMJS_CONSOLE_PREFIX = "phantomjs> ";
54 | private static final List DEFAULT_PHANTOMJS_CONSOLE_POSTFIXS = asList("{}", "undefined");
55 | private static final String PHANTOMJS_PARSER_ERROR_PREFIX = "Parse error";
56 |
57 | private final ExecutorService executorService = Executors.newSingleThreadExecutor();
58 | private final PhantomJSReference phantomReference;
59 | private final File scriptFile;
60 | private final String scriptArgs[];
61 | private final String consolePrefix;
62 | private final List consolePostfix;
63 | private Process process;
64 |
65 | public PhantomJSConsoleExecutor(final PhantomJSReference phantomReference) {
66 | this(phantomReference, null);
67 | }
68 |
69 | public PhantomJSConsoleExecutor(final PhantomJSReference phantomReference, final File scriptFile, final String... scriptArgs) {
70 | this(phantomReference, DEFAULT_PHANTOMJS_CONSOLE_PREFIX, DEFAULT_PHANTOMJS_CONSOLE_POSTFIXS, scriptFile, scriptArgs);
71 | }
72 |
73 | public PhantomJSConsoleExecutor(final PhantomJSReference phantomReference, final String consolePrefix, final List consolePostfix, final File scriptFile, final String... scriptArgs) {
74 | this.phantomReference = phantomReference;
75 | this.scriptFile = scriptFile;
76 | this.scriptArgs = scriptArgs;
77 | this.consolePrefix = consolePrefix;
78 | this.consolePostfix = consolePostfix;
79 | }
80 |
81 | public int getPid() {
82 | if (process.getClass().getName().equals("java.lang.UNIXProcess")) {
83 | /* get the PID on unix/linux systems */
84 | try {
85 | Field f = process.getClass().getDeclaredField("pid");
86 | f.setAccessible(true);
87 | return f.getInt(process);
88 | } catch (Throwable e) {
89 | }
90 | }
91 |
92 | return -1;
93 | }
94 |
95 | public boolean isAlive() {
96 | try {
97 | process.exitValue();
98 | return false;
99 | } catch (IllegalThreadStateException ex) {
100 | return true;
101 | }
102 | }
103 |
104 | public void start() {
105 | try {
106 | String cmd = this.phantomReference.getBinaryPath();
107 |
108 | if (scriptFile != null) {
109 | cmd = cmd + " " + scriptFile.getAbsolutePath();
110 | }
111 |
112 | if (scriptArgs != null && scriptArgs.length > 0) {
113 | cmd = cmd + " " + StringUtils.join(scriptArgs, " ");
114 | }
115 |
116 | process = Runtime.getRuntime().exec(cmd);
117 | if (StringUtils.isNotBlank(consolePrefix)) {
118 | process.getInputStream().read(new byte[consolePrefix.length()]);
119 | }
120 | } catch (IOException e) {
121 | throw new RuntimeException(e);
122 | }
123 | }
124 |
125 | public int destroy() {
126 | try {
127 | process.destroy();
128 | } catch (Exception e) {
129 | }
130 |
131 | if (isAlive()) {
132 | try {
133 | return process.waitFor();
134 | } catch (InterruptedException e) {
135 |
136 | }
137 | }
138 |
139 | return process.exitValue();
140 | }
141 |
142 | public CompletableFuture execute(final String scriptSource) {
143 | return this.execute(IOUtils.toInputStream(scriptSource, Charset.defaultCharset()), consolePostfix);
144 | }
145 |
146 | public CompletableFuture execute(final String scriptSource, String... endLines) {
147 | return this.execute(IOUtils.toInputStream(scriptSource, Charset.defaultCharset()), asList(endLines));
148 | }
149 |
150 | public CompletableFuture execute(final InputStream scriptSourceInputStream, String... endLines) {
151 | return this.execute(scriptSourceInputStream, asList(endLines));
152 | }
153 |
154 | public CompletableFuture execute(final InputStream scriptSourceInputStream, final List endLines)
155 | throws UnexpectedProcessEndException {
156 | return CompletableFuture.supplyAsync(() -> doExecute(scriptSourceInputStream, endLines), executorService);
157 | }
158 |
159 | private String doExecute(final InputStream scriptSourceInputStream, final List endLines) {
160 |
161 | if (!isAlive()) {
162 | throw new UnexpectedProcessEndException();
163 | }
164 |
165 | try {
166 | final String input = copy(scriptSourceInputStream, process.getOutputStream());
167 | // Append Enter to the input
168 |
169 | if (!endWithNewLine(input)) {
170 | for (char c : SYSTEM_NEWLINE) {
171 | process.getOutputStream().write(c);
172 | }
173 | }
174 |
175 | process.getOutputStream().flush();
176 |
177 | final String output = readPhantomJSOutput(process.getInputStream(), endLines);
178 |
179 | LOGGER.debug("Program output: " + output);
180 |
181 | return output;
182 | } catch (IOException e) {
183 | throw new UnexpectedProcessEndException(e);
184 | }
185 | }
186 |
187 | private String readPhantomJSOutput(InputStream processInput, List endLines) throws IOException {
188 | final StringBuilder out = new StringBuilder();
189 | final BufferedReader in = new BufferedReader(new InputStreamReader(processInput, "UTF-8"));
190 |
191 | while (true) {
192 | final String line = in.readLine();
193 |
194 | LOGGER.trace("Incoming line from process: " + line);
195 |
196 | if (line.equals(PHANTOMJS_PARSER_ERROR_PREFIX)) {
197 | return line;
198 | }
199 |
200 | if (line == null || endLines.contains(line)) {
201 | if (StringUtils.isNotBlank(consolePrefix)) {
202 | in.skip(consolePrefix.length());
203 | }
204 | break;
205 | }
206 |
207 | if (out.length() > 0) {
208 | out.append("\n");
209 | }
210 |
211 | out.append(line);
212 | }
213 |
214 | return out.toString();
215 | }
216 |
217 | private boolean endWithNewLine(final String input) {
218 | return input.endsWith(String.valueOf(SYSTEM_NEWLINE));
219 | }
220 |
221 | private String copy(final InputStream input, final OutputStream output) throws IOException {
222 | final StringBuilder inputString = new StringBuilder();
223 | final byte[] buffer = new byte[DEFAULT_BUFFER_SIZE];
224 | int n = 0;
225 | while (EOF != (n = input.read(buffer))) {
226 | output.write(buffer, 0, n);
227 | inputString.append(new String(buffer, 0, n));
228 | }
229 | return inputString.toString();
230 | }
231 |
232 | public String getConsolePrefix() {
233 | return consolePrefix;
234 | }
235 | public List getConsolePostfix() {
236 | return consolePostfix;
237 | }
238 | }
239 |
--------------------------------------------------------------------------------
/src/main/java/com/github/jarlakxen/embedphantomjs/executor/PhantomJSFileExecutor.java:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright (C) 2013
3 | * Facundo Viale
4 | *
5 | * with contributions from
6 | * Facundo Viale (Jarlakxen@github)
7 | *
8 | * Licensed under the Apache License, Version 2.0 (the "License");
9 | * you may not use this file except in compliance with the License.
10 | * You may obtain a copy of the License at
11 | *
12 | * http://www.apache.org/licenses/LICENSE-2.0
13 | *
14 | * Unless required by applicable law or agreed to in writing, software
15 | * distributed under the License is distributed on an "AS IS" BASIS,
16 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17 | * See the License for the specific language governing permissions and
18 | * limitations under the License.
19 | */
20 | package com.github.jarlakxen.embedphantomjs.executor;
21 |
22 | import java.io.File;
23 | import java.nio.charset.Charset;
24 | import java.util.concurrent.CompletableFuture;
25 | import java.util.concurrent.ExecutorService;
26 | import java.util.concurrent.Executors;
27 | import java.util.function.Function;
28 |
29 | import org.apache.commons.io.FileUtils;
30 | import org.apache.commons.io.IOUtils;
31 | import org.apache.commons.lang3.RandomStringUtils;
32 | import org.apache.commons.lang3.StringUtils;
33 | import org.apache.log4j.Logger;
34 |
35 | import com.github.jarlakxen.embedphantomjs.ExecutionTimeout;
36 | import com.github.jarlakxen.embedphantomjs.PhantomJSReference;
37 |
38 | public class PhantomJSFileExecutor {
39 |
40 | private static final Logger LOGGER = Logger.getLogger(PhantomJSFileExecutor.class);
41 |
42 | private final ExecutorService processExecutorService;
43 |
44 | private final PhantomJSReference phantomReference;
45 |
46 | private final ExecutionTimeout executionTimeout;
47 |
48 | public PhantomJSFileExecutor(PhantomJSReference phantomReference, ExecutionTimeout executionTimeout) {
49 | this(phantomReference, Executors.newCachedThreadPool(), executionTimeout);
50 | }
51 |
52 | public PhantomJSFileExecutor(final PhantomJSReference phantomReference, final ExecutorService executorService,
53 | final ExecutionTimeout executionTimeout) {
54 | this.phantomReference = phantomReference;
55 | this.executionTimeout = executionTimeout;
56 | this.processExecutorService = executorService;
57 | }
58 |
59 | public CompletableFuture execute(final String fileContent, final String... args) {
60 | try {
61 | final File tmp = File.createTempFile(RandomStringUtils.randomAlphabetic(10), ".js");
62 | FileUtils.write(tmp, fileContent, Charset.defaultCharset());
63 | final CompletableFuture result = execute(tmp, args);
64 |
65 | return result.handle((value, error) -> {
66 | if (tmp != null) {
67 | tmp.delete();
68 | }
69 |
70 | if (error == null){
71 | return CompletableFuture.completedFuture(value);
72 | }
73 |
74 | LOGGER.error("", error);
75 | final CompletableFuture errorFuture = new CompletableFuture<>();
76 | errorFuture.completeExceptionally(error);
77 | return errorFuture;
78 | }).thenCompose(Function.identity());
79 | } catch (Exception e) {
80 | throw new RuntimeException(e);
81 | }
82 | }
83 |
84 | /**
85 | * Invokes the instances of PhantomJS
86 | *
87 | * @param sourceFile
88 | * JavaScript source file that is executed by PhantomJA
89 | * @param args
90 | * Parameters that are read by sourceFile
91 | * @return The result that the process has output in console
92 | */
93 | public CompletableFuture execute(final File sourceFile, final String... args) {
94 | final String cmd = this.phantomReference.getBinaryPath() + " " + this.phantomReference.getCommandLineOptions()
95 | + " " + sourceFile.getAbsolutePath() + " " + StringUtils.join(args, " ");
96 | try {
97 | final Process process = Runtime.getRuntime().exec(cmd);
98 | LOGGER.info("Command to execute: " + cmd);
99 |
100 | final CompletableFuture action = CompletableFuture.supplyAsync(() -> {
101 | try {
102 | LOGGER.info("Command to execute: " + cmd);
103 | final String output = IOUtils.toString(process.getInputStream(), Charset.defaultCharset());
104 | process.waitFor();
105 | LOGGER.debug("Command " + cmd + " output:" + output);
106 | return output;
107 | } catch (Exception e) {
108 | throw new RuntimeException(e);
109 | }
110 | }, processExecutorService);
111 |
112 | CompletableFuture.runAsync(() -> {
113 | try {
114 | action.get(executionTimeout.getTimeout(), executionTimeout.getUnit());
115 | } catch (Exception ex) {
116 | action.completeExceptionally(ex);
117 | process.destroy();
118 | }
119 | });
120 |
121 | return action;
122 | } catch (Exception e) {
123 | throw new RuntimeException(e);
124 | }
125 | }
126 | }
127 |
--------------------------------------------------------------------------------
/src/main/resources/etc/license.txt:
--------------------------------------------------------------------------------
1 | Copyright (C) ${lic.year}
2 | ${lic.username}
3 |
4 | with contributions from
5 | ${lic.developers}
6 |
7 | Licensed under the Apache License, Version 2.0 (the "License");
8 | you may not use this file except in compliance with the License.
9 | You may obtain a copy of the License at
10 |
11 | http://www.apache.org/licenses/LICENSE-2.0
12 |
13 | Unless required by applicable law or agreed to in writing, software
14 | distributed under the License is distributed on an "AS IS" BASIS,
15 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 | See the License for the specific language governing permissions and
17 | limitations under the License.
--------------------------------------------------------------------------------
/src/main/resources/phantomjs/data.properties:
--------------------------------------------------------------------------------
1 | 2.1.1.linux.name = phantomjs-2.1.1-linux-%s.tar.bz2
2 | 2.1.1.win.name = phantomjs-2.1.1-windows.zip
3 | 2.1.1.macosx.name = phantomjs-2.1.1-macosx.zip
4 |
5 | 1.9.8.linux.name = phantomjs-1.9.8-linux-%s.tar.bz2
6 | 1.9.8.win.name = phantomjs-1.9.8-windows.zip
7 | 1.9.8.macosx.name = phantomjs-1.9.8-macosx.zip
8 |
9 | 1.9.7.linux.name = phantomjs-1.9.7-linux-%s.tar.bz2
10 | 1.9.7.win.name = phantomjs-1.9.7-windows.zip
11 | 1.9.7.macosx.name = phantomjs-1.9.7-macosx.zip
12 |
13 | 1.9.6.linux.name = phantomjs-1.9.6-linux-%s.tar.bz2
14 | 1.9.6.win.name = phantomjs-1.9.6-windows.zip
15 | 1.9.6.macosx.name = phantomjs-1.9.6-macosx.zip
16 |
17 | 1.9.5.linux.name = phantomjs-1.9.5-linux-%s.tar.bz2
18 | 1.9.5.win.name = phantomjs-1.9.5-windows.zip
19 | 1.9.5.macosx.name = phantomjs-1.9.5-macosx.zip
20 |
21 | 1.9.4.linux.name = phantomjs-1.9.4-linux-%s.tar.bz2
22 | 1.9.4.win.name = phantomjs-1.9.4-windows.zip
23 | 1.9.4.macosx.name = phantomjs-1.9.4-macosx.zip
24 |
25 | 1.9.3.linux.name = phantomjs-1.9.3-linux-%s.tar.bz2
26 | 1.9.3.win.name = phantomjs-1.9.3-windows.zip
27 | 1.9.3.macosx.name = phantomjs-1.9.3-macosx.zip
28 |
29 | 1.9.2.linux.name = phantomjs-1.9.2-linux-%s.tar.bz2
30 | 1.9.2.win.name = phantomjs-1.9.2-windows.zip
31 | 1.9.2.macosx.name = phantomjs-1.9.2-macosx.zip
32 |
33 | 1.9.1.linux.name = phantomjs-1.9.1-linux-%s.tar.bz2
34 | 1.9.1.win.name = phantomjs-1.9.1-windows.zip
35 | 1.9.1.macosx.name = phantomjs-1.9.1-macosx.zip
36 |
37 | 1.9.0.linux.name = phantomjs-1.9.0-linux-%s.tar.bz2
38 | 1.9.0.win.name = phantomjs-1.9.0-windows.zip
39 | 1.9.0.macosx.name = phantomjs-1.9.0-macosx.zip
40 |
41 | 1.8.2.linux.name = phantomjs-1.8.2-linux-%s.tar.bz2
42 | 1.8.2.win.name = phantomjs-1.8.2-windows.zip
43 | 1.8.2.macosx.name = phantomjs-1.8.2-macosx.zip
44 |
45 | 1.8.1.linux.name = phantomjs-1.8.1-linux-%s.tar.bz2
46 | 1.8.1.win.name = phantomjs-1.8.1-windows.zip
47 | 1.8.1.macosx.name = phantomjs-1.8.1-macosx.zip
48 |
49 | 1.8.0.linux.name = phantomjs-1.8.0-linux-%s.tar.bz2
50 | 1.8.0.win.name = phantomjs-1.8.0-windows.zip
51 | 1.8.0.macosx.name = phantomjs-1.8.0-macosx.zip
52 |
53 | 1.7.0.linux.name = phantomjs-1.7.0-linux-%s.tar.bz2
54 | 1.7.0.win.name = phantomjs-1.7.0-windows.zip
55 | 1.7.0.macosx.name = phantomjs-1.7.0-macosx.zip
56 |
57 | 1.6.1.linux.name = phantomjs-1.6.1-linux-%s-dynamic.tar.bz2
58 | 1.6.1.win.name = phantomjs-1.6.1-win32-static.zip
59 | 1.6.1.macosx.name = phantomjs-1.6.1-macosx-static.zip
60 |
61 | 1.6.0.linux.name = phantomjs-1.6.0-linux-%s-dynamic.tar.bz2
62 | 1.6.0.win.name = phantomjs-1.6.0-win32-static.zip
63 | 1.6.0.macosx.name = phantomjs-1.6.0-macosx-static.zip
64 |
65 | 1.5.0.linux.name = phantomjs-1.5.0-linux-%s-dynamic.tar.gz
66 | 1.5.0.win.name = phantomjs-1.5.0-win32-static.zip
67 | 1.5.0.macosx.name = phantomjs-1.5.0-macosx-static.zip
68 |
69 | 1.4.1.linux.name = phantomjs-1.4.1-linux-%s-dynamic.tar.gz
70 | 1.4.1.win.name = phantomjs-1.4.1-win32-static.zip
71 | 1.4.1.macosx.name = phantomjs-1.4.1-macosx-static.zip
--------------------------------------------------------------------------------
/src/test/java/com/github/jarlakxen/embedphantomjs/PhantomJSExecutorTest.java:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright (C) 2013
3 | * Facundo Viale
4 | *
5 | * with contributions from
6 | * Facundo Viale (Jarlakxen@github)
7 | *
8 | * Licensed under the Apache License, Version 2.0 (the "License");
9 | * you may not use this file except in compliance with the License.
10 | * You may obtain a copy of the License at
11 | *
12 | * http://www.apache.org/licenses/LICENSE-2.0
13 | *
14 | * Unless required by applicable law or agreed to in writing, software
15 | * distributed under the License is distributed on an "AS IS" BASIS,
16 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17 | * See the License for the specific language governing permissions and
18 | * limitations under the License.
19 | */
20 | package com.github.jarlakxen.embedphantomjs;
21 |
22 | import static org.junit.Assert.assertEquals;
23 |
24 | import java.io.File;
25 | import java.io.IOException;
26 | import java.nio.charset.Charset;
27 | import java.util.concurrent.CompletableFuture;
28 | import java.util.concurrent.ExecutionException;
29 | import java.util.concurrent.TimeUnit;
30 |
31 | import org.apache.commons.io.FileUtils;
32 | import org.junit.AfterClass;
33 | import org.junit.BeforeClass;
34 | import org.junit.Test;
35 |
36 | import com.github.jarlakxen.embedphantomjs.exception.UnexpectedProcessEndException;
37 | import com.github.jarlakxen.embedphantomjs.executor.PhantomJSConsoleExecutor;
38 | import com.github.jarlakxen.embedphantomjs.executor.PhantomJSFileExecutor;
39 |
40 | public class PhantomJSExecutorTest {
41 |
42 | private static final String DEFAULT_FILE_JS = "console.log('TEST1');phantom.exit();";
43 | private static final String DEFAULT_CONSOLE_BOOTSTRAP = "var system = require('system');";
44 | private static final String DEFAULT_CONSOLE_JS = "system.standardout.writeLine('TEST1')";
45 |
46 | private static final File test1 = new File(System.getProperty("java.io.tmpdir") + "/embedphantomjs.test1.js");
47 |
48 | private static final PhantomJSReference phantomJSRef = PhantomJSReference.create().build();
49 |
50 | @BeforeClass
51 | public static void setUpClass() throws IOException {
52 | test1.createNewFile();
53 | FileUtils.write(test1, DEFAULT_FILE_JS, Charset.defaultCharset());
54 | phantomJSRef.ensureBinary();
55 | }
56 |
57 | @AfterClass
58 | public static void tearDownClass() throws IOException {
59 | test1.delete();
60 | }
61 |
62 | @Test
63 | public void test_FileExecutor_FromString() throws InterruptedException, ExecutionException {
64 | PhantomJSFileExecutor ex = new PhantomJSFileExecutor(phantomJSRef, new ExecutionTimeout(5, TimeUnit.SECONDS));
65 | assertEquals("TEST1"+String.format("%n"), ex.execute(DEFAULT_FILE_JS).get());
66 | }
67 |
68 | @Test
69 | public void test__FileExecutor_FromFile() throws InterruptedException, ExecutionException {
70 | PhantomJSFileExecutor ex = new PhantomJSFileExecutor(phantomJSRef, new ExecutionTimeout(5, TimeUnit.SECONDS));
71 | assertEquals("TEST1"+String.format("%n"), ex.execute(test1).get());
72 | }
73 |
74 | @Test
75 | public void test_FileExecutor_FromString_Timeout() throws InterruptedException, ExecutionException {
76 | PhantomJSFileExecutor ex = new PhantomJSFileExecutor(phantomJSRef, new ExecutionTimeout(100, TimeUnit.MILLISECONDS));
77 | CompletableFuture result = ex.execute("while(true){};");
78 | Thread.sleep(200);
79 | assertEquals(true,result.isDone());
80 | assertEquals(true,result.isCompletedExceptionally());
81 | }
82 |
83 | @Test
84 | public void test_executor_FromConsole() throws UnexpectedProcessEndException, InterruptedException, ExecutionException {
85 | PhantomJSConsoleExecutor ex = new PhantomJSConsoleExecutor(phantomJSRef);
86 | ex.start();
87 | ex.execute(DEFAULT_CONSOLE_BOOTSTRAP).get();
88 | assertEquals("TEST1", ex.execute(DEFAULT_CONSOLE_JS, "true").get());
89 | assertEquals("TEST1", ex.execute(DEFAULT_CONSOLE_JS, "true").get());
90 | ex.destroy();
91 | }
92 | }
93 |
--------------------------------------------------------------------------------