001/* 002 * (C) Copyright 2006-2016 Nuxeo SA (http://nuxeo.com/) and others. 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * http://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 * 016 * Contributors: 017 * bstefanescu 018 */ 019package org.nuxeo.runtime.test.runner; 020 021import java.io.File; 022import java.io.IOException; 023import java.io.InputStream; 024import java.lang.reflect.Field; 025import java.net.URL; 026 027import org.apache.commons.io.FileUtils; 028import org.nuxeo.runtime.test.WorkingDirectoryConfigurator; 029 030import sun.net.www.http.HttpClient; 031 032/** 033 * Runs an embedded Jetty server with the nuxeo webapp deployed. 034 * <p> 035 * Note that at initialization the feature disables the {@code retryPostProp} property of 036 * {@link sun.net.www.http.HttpClient}, the underlying HTTP client used by {@link com.sun.jersey.api.client.Client}. 037 * <p> 038 * This is to prevent the JDK's default behavior kept for backward compatibility: an unsuccessful HTTP POST request is 039 * automatically resent to the server, unsuccessful in this case meaning the server did not send a valid HTTP response 040 * or an {@code IOException} occurred. Yet in the tests using the Jersey client to make calls to Nuxeo we don't want 041 * this as it can hide errors occurring in the HTTP communication that should prevent an appropriate response from being 042 * sent by the server. 043 */ 044@Deploy("org.nuxeo.runtime.jetty") 045@Features(RuntimeFeature.class) 046public class JettyFeature extends SimpleFeature implements WorkingDirectoryConfigurator { 047 048 @Override 049 public void initialize(FeaturesRunner runner) throws Exception { 050 disableSunHttpClientRetryPostProp(); 051 052 Jetty jetty = runner.getConfig(Jetty.class); 053 if (jetty == null) { 054 jetty = Defaults.of(Jetty.class); 055 } 056 configureJetty(jetty); 057 058 runner.getFeature(RuntimeFeature.class).getHarness().addWorkingDirectoryConfigurator(this); 059 } 060 061 protected void configureJetty(Jetty jetty) { 062 int p = jetty.port(); 063 try { 064 String s = System.getenv("JETTY_PORT"); 065 if (s != null) { 066 p = Integer.parseInt(s); 067 } 068 } catch (Exception e) { 069 // do nothing ; the jetty.port 070 } 071 if (p > 0) { 072 System.setProperty("jetty.port", Integer.toString(p)); 073 } 074 075 String host = System.getenv("JETTY_HOST"); 076 if (host == null) { 077 host = jetty.host(); 078 } 079 if (host.length() > 0) { 080 System.setProperty("jetty.host", host); 081 } 082 083 String config = System.getenv("JETTY_CONFIG"); 084 if (config == null) { 085 config = jetty.config(); 086 } 087 if (config.length() > 0) { 088 System.setProperty("org.nuxeo.jetty.config", config); 089 } 090 091 System.setProperty("org.nuxeo.jetty.propagateNaming", Boolean.toString(jetty.propagateNaming())); 092 } 093 094 @Override 095 public void configure(RuntimeHarness harness, File workingDir) throws IOException { 096 File dest = new File(workingDir, "config"); 097 dest.mkdirs(); 098 099 dest = new File(workingDir + "/config", "default-web.xml"); 100 try (InputStream in = getResource("jetty/default-web.xml").openStream()) { 101 FileUtils.copyInputStreamToFile(in, dest); 102 } 103 104 dest = new File(workingDir + "/config", "jetty.xml"); 105 try (InputStream in = getResource("jetty/jetty.xml").openStream()) { 106 FileUtils.copyInputStreamToFile(in, dest); 107 } 108 } 109 110 private static URL getResource(String resource) { 111 // return 112 // Thread.currentThread().getContextClassLoader().getResource(resource); 113 return Jetty.class.getClassLoader().getResource(resource); 114 } 115 116 /** 117 * Prevents the JDK's default behavior of resending an unsuccessful HTTP POST request automatically to the server by 118 * disabling the the {@code retryPostProp} property of {@link sun.net.www.http.HttpClient}. 119 * <p> 120 * This can also be achieved by setting the {@code sun.net.http.retryPost} system property to {@code false}. 121 * 122 * @since 9.3 123 */ 124 public static void disableSunHttpClientRetryPostProp() 125 throws NoSuchFieldException, SecurityException, IllegalArgumentException, IllegalAccessException { 126 Field field = HttpClient.class.getDeclaredField("retryPostProp"); 127 field.setAccessible(true); 128 field.setBoolean(null, false); 129 } 130 131}