View Javadoc

1   /*
2    * Copyright 2012 smartics, Kronseder & Reiner GmbH
3    *
4    * Licensed under the Apache License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    *
8    *     http://www.apache.org/licenses/LICENSE-2.0
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   */
16  package de.smartics.ci.comm.hudson.command;
17  
18  import java.io.IOException;
19  import java.io.InputStream;
20  import java.util.Map.Entry;
21  import java.util.Properties;
22  import java.util.regex.Pattern;
23  
24  import org.apache.commons.httpclient.methods.PostMethod;
25  import org.apache.commons.io.IOUtils;
26  import org.slf4j.Logger;
27  import org.slf4j.LoggerFactory;
28  
29  import de.smartics.ci.comm.LogHelper;
30  import de.smartics.ci.comm.command.AbstractGenericJobCommand;
31  import de.smartics.ci.comm.command.Command;
32  import de.smartics.ci.comm.command.CommandException;
33  import de.smartics.ci.comm.command.CommandResult;
34  import de.smartics.ci.comm.command.InvalidRequestException;
35  
36  /**
37   * This abstract class contains the functionality to handle jobs calling an api.
38   * It handles the replacement of variables in the api call and handles methods
39   * to handle the response.
40   *
41   * @param <T> the concrete type of the command.
42   */
43  public abstract class AbstractHudsonApiJob<T extends Command<T>> extends
44      AbstractGenericJobCommand<T>
45  {
46  
47    /**
48     * Reference to the logger for this class.
49     */
50    private static final Logger LOG = LoggerFactory
51        .getLogger(AbstractHudsonApiJob.class);
52  
53    /**
54     * Delimiter, used for logging.
55     */
56    private static final String BOCKDELIMITER = "-------------------------------";
57  
58    /**
59     * The xmlQuery string to execute against the xml api.
60     */
61    protected String xmlQueryString;
62  
63    /**
64     * Key value pairs / properties used to replace variables (the keys) in the
65     * xml query string with the values.
66     */
67    protected Properties properties;
68  
69    /**
70     * The result of this command.
71     */
72    protected CommandResult<T> commandResult;
73  
74    /**
75     * Default constructor.
76     *
77     * @param jobName the name of the job.
78     */
79    public AbstractHudsonApiJob(final String jobName)
80    {
81      super(jobName);
82    }
83  
84    /**
85     * Sets the xmlQuery string to execute against the xml api.
86     *
87     * @param xmlQueryString the xmlQuery string to execute against the xml api.
88     */
89    public final void setXmlQueryString(final String xmlQueryString)
90    {
91      this.xmlQueryString = xmlQueryString;
92    }
93  
94    /**
95     * Sets the value for keyValuePairs.
96     * <p>
97     * Key value pairs used to replace variables (the keys) in the xml query
98     * string with the values.
99     *
100    * @param properties the value for keyValuePairs.
101    */
102   public final void setKeyValuePairs(final Properties properties)
103   {
104     this.properties = properties;
105     if (this.properties == null)
106     {
107       this.properties = new Properties();
108     }
109   }
110 
111   /**
112    * Create the command result and provide the result object in this command
113    * object.
114    *
115    * @param statusCode the status code of the response.
116    * @param method the method used to execute the command.
117    * @throws IOException when the communication fails and the response could not
118    *           be retrieved.
119    * @throws CommandException when command fails.
120    */
121   protected final void createResult(final int statusCode,
122       final PostMethod method) throws IOException, CommandException
123   {
124 
125     final String response = getResponseAsString(method);
126     final CommandResult<T> result =
127         new CommandResult<T>(statusCode, new CommandResult.HttpStatus(
128             statusCode, method.getStatusText()), response);
129     this.commandResult = result;
130     logResult(statusCode, response);
131   }
132 
133   private void logResult(final int statusCode, final String response)
134     throws CommandException, InvalidRequestException
135   {
136     if (statusCode / ERROR_CATEGORY_DESTINGUISHER == 2)
137     {
138       LogHelper.logInfo(LOG, logLevel,
139           "HTTP status 'OK' has been returned from server.");
140       checkResponseString(response);
141     }
142     else
143     {
144       if (response.contains("lieferte keinen Treffer")
145           || response.contains("didn't match"))
146       {
147         LogHelper.logError(LOG, logLevel,
148             "Server returned that query did not match.");
149       }
150       else
151       {
152         checkResultRegardingRedirect(statusCode);
153       }
154     }
155   }
156 
157   private String getResponseAsString(final PostMethod method)
158     throws IOException
159   {
160     final InputStream responseStream = method.getResponseBodyAsStream();
161     final String response = IOUtils.toString(responseStream);
162     return response;
163   }
164 
165   /**
166    * Check the response.
167    *
168    * @param response the response.
169    * @throws CommandException when check fails.
170    */
171   protected void checkResponseString(final String response)
172     throws CommandException
173   {
174   }
175 
176   /**
177    * Log the response of this command.
178    *
179    * @param response the response as String.
180    * @throws IOException when the response can not be retrieved from the method.
181    */
182   protected final void logResponse(final String response) throws IOException
183   {
184     LogHelper.logInfo(LOG, logLevel, BOCKDELIMITER);
185     LogHelper.logInfo(LOG, logLevel, "\n\r");
186     LogHelper.logInfo(LOG, logLevel, response);
187     LogHelper.logInfo(LOG, logLevel, "\n\r");
188     LogHelper.logInfo(LOG, logLevel, BOCKDELIMITER);
189   }
190 
191   /**
192    * Resolve the query string, resolve all variables in the query string with
193    * the given values.
194    *
195    * @param queryString the query string containing variables.
196    * @return a query string with replaced variables.
197    */
198   protected final String resolve(final String queryString)
199   {
200     String result = queryString;
201 
202     for (@SuppressWarnings("rawtypes")
203     final Entry entry : properties.entrySet())
204     {
205       result =
206           replace(result, entry.getKey().toString(), entry.getValue()
207               .toString());
208     }
209 
210     if (!checkKeyValuesContainJobName())
211     {
212       result = replace(result, "jobName", jobName);
213     }
214     return result;
215   }
216 
217   @Override
218   public final CommandResult<T> getResult()
219   {
220     return this.commandResult;
221   }
222 
223   private String replace(final String input, final String key,
224       final String value)
225   {
226     return input.replaceAll(Pattern.quote("${" + key + "}"), value).replaceAll(
227         Pattern.quote("@{" + key + "}"), value);
228   }
229 
230   private boolean checkKeyValuesContainJobName()
231   {
232     return properties.containsKey("jobName");
233   }
234 
235 }