Java tutorial
/* * Copyright 2011 by EDINA, University of Edinburgh * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ package edina.eframework.gefcdemo.controllers; import java.io.ByteArrayInputStream; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.StringWriter; import java.io.UnsupportedEncodingException; import java.io.Writer; import java.net.MalformedURLException; import java.net.URL; import java.util.HashMap; import java.util.Map; import javax.xml.bind.JAXBContext; import javax.xml.bind.JAXBException; import javax.xml.bind.Unmarshaller; import org.apache.commons.httpclient.HttpClient; import org.apache.commons.httpclient.SimpleHttpConnectionManager; import org.apache.commons.httpclient.methods.PostMethod; import org.apache.commons.httpclient.methods.RequestEntity; import org.apache.commons.httpclient.methods.StringRequestEntity; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.apache.velocity.app.VelocityEngine; import org.springframework.stereotype.Controller; import org.springframework.ui.velocity.VelocityEngineUtils; import org.springframework.web.bind.annotation.ModelAttribute; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; import edina.eframework.gefcdemo.domain.SoilErosionWps; import edina.eframework.gefcdemo.domain.WpsResponse; import edina.eframework.gefcdemo.generated.wps.ExecuteResponse; import edina.eframework.gefcdemo.portrayal.MapserverGenerator; /** * This controller drives the processing of the soil erosion algorithm. This * generates the WPS request, sends the request and processes the response. The * controller is called by two AJAX requests, one to process the landcover * preview, and the other to go ahead and process the full soil erosion model. * * @author Andrew Seales */ @Controller @RequestMapping(value = "/processmodel") public class ProcessErosionController { private static final Log log = LogFactory.getLog(ProcessErosionController.class); // Velocity object generated by Spring private VelocityEngine velocityEngine; public void setVelocityEngine(VelocityEngine velocityEngine) { this.velocityEngine = velocityEngine; } // Classpath location of the WPS request template for processing the model private String templateLocation; public void setTemplateLocation(String templateLocation) { this.templateLocation = templateLocation; } // Classpath location of the WPS request template for previewing landcover private String growTemplateLocation; public void setGrowTemplateLocation(String growTemplateLocation) { this.growTemplateLocation = growTemplateLocation; } // URL to the WPS server minus parameters. A POST request is made to this. private URL wpsServer; public void setWpsServer(URL wpsServer) { this.wpsServer = wpsServer; } // Base output folder where the data from the WPS is saved private String wpsOutputDir; public void setWpsOutputDir(String wpsOutputDir) { this.wpsOutputDir = wpsOutputDir; } // Object which generates Mapserver WMS mapfiles private MapserverGenerator mapserverGenerator; public void setMapserverGenerator(MapserverGenerator mapserverGenerator) { this.mapserverGenerator = mapserverGenerator; } /** * Testing method for entering a mock model. */ @RequestMapping(method = RequestMethod.GET) public String handleProcess(SoilErosionWps params) { return "wps"; } /** * Method requested by the landcover preview button. * * @param params parameters used when calculating the soil erosion model * @return the main gefcdemo view, i.e., updates the controls panel * @throws IOException * @throws JAXBException */ @RequestMapping(method = RequestMethod.POST, params = "ajaxSource=previewGrow") public String handlePreviewGrow(SoilErosionWps params) throws IOException, JAXBException { generateWpsRequest(params, new WpsResponse(), growTemplateLocation, wpsOutputDir + "/aseales/landcoverPreview.tiff"); mapserverGenerator.generateLandcoverConfiguration("aseales"); return "gefcdemo"; } /** * Method requested by the process soil erosion button. * * @param params parameters used when calculating the soil erosion model * @param wpsResponse results from WPS process written to this object * @return the main gefcdemo view, i.e., updates the control panel * @throws IOException * @throws JAXBException */ @RequestMapping(method = RequestMethod.POST, params = "ajaxSource=submitProcess") public String handleProcessResult(SoilErosionWps params, @ModelAttribute("wpsResponse") WpsResponse wpsResponse) throws IOException, JAXBException { generateWpsRequest(params, wpsResponse, templateLocation, wpsOutputDir + "/aseales/result.tiff"); mapserverGenerator.generateResultConfiguration("aseales"); return "gefcdemo"; } /** * Brokers the WPS request and response. Supports two different WPS requests, * the landcover preview and the process soil erosion model requests. * * @param params parameters used when calculating the soil erosion model * @param wpsResponse results from the WPS process are written to this object * @param template the VM template to use to generate the WPS request * @param wpsOutputFile the filename to write the TIFF result file * @throws IOException * @throws JAXBException */ private void generateWpsRequest(SoilErosionWps params, WpsResponse wpsResponse, String template, String wpsOutputFile) throws IOException, JAXBException { Writer wpsRequest = new StringWriter(); Map<String, Object> velocityMap = new HashMap<String, Object>(); velocityMap.put("params", params); VelocityEngineUtils.mergeTemplate(velocityEngine, template, velocityMap, wpsRequest); wpsRequest.close(); log.debug(wpsRequest.toString()); log.debug("Submitting to " + wpsServer); RequestEntity entity = null; try { entity = new StringRequestEntity(wpsRequest.toString(), "text/xml", "UTF-8"); } catch (UnsupportedEncodingException e) { throw new MalformedURLException("Apparantly 'UTF-8' is an unsupported encoding type."); } PostMethod post = new PostMethod(wpsServer.toString()); post.setRequestEntity(entity); HttpClient client = new HttpClient(new SimpleHttpConnectionManager()); client.getHttpConnectionManager().getParams().setSoTimeout(0); client.getHttpConnectionManager().getParams().setConnectionTimeout(0); client.executeMethod(post); JAXBContext jaxbContext = JAXBContext.newInstance("edina.eframework.gefcdemo.generated.wps"); Unmarshaller unmarshaller = jaxbContext.createUnmarshaller(); ExecuteResponse executeResponse = null; // First save post data into a String so we can log any potential errors. // Response isn't very large from the WPS so this shouldn't be a problem. // Trying to access post data if a direct InputStream is passed to unmarshal // doesn't work. String postData = post.getResponseBodyAsString(); try { executeResponse = (ExecuteResponse) unmarshaller .unmarshal(new ByteArrayInputStream(postData.getBytes())); } catch (ClassCastException e) { log.error("Error from WPS:\n" + postData); throw e; } //executeResponse.getStatus().getProcessAccepted(); // TODO check for failed String resultUrl = executeResponse.getProcessOutputs().getOutput().get(0).getReference().getHref(); log.debug("Output " + resultUrl); wpsResponse.setOutputUrl(new URL(resultUrl)); wpsResponse.setOutputId(resultUrl.substring(resultUrl.lastIndexOf("id=") + 3, resultUrl.length())); wpsResponse.setStatus(200); // Save the WPS output data to a file mapserver can use File resultOutputFile = new File(wpsOutputFile); resultOutputFile.getParentFile().mkdirs(); FileOutputStream resultFileStream = new FileOutputStream(resultOutputFile); InputStream resultInputFile = null; try { resultInputFile = wpsResponse.getOutputUrl().openStream(); byte[] buffer = new byte[4096]; int i; while ((i = resultInputFile.read(buffer)) != -1) { resultFileStream.write(buffer, 0, i); } resultFileStream.flush(); } finally { try { resultInputFile.close(); } catch (Exception e) { } try { resultFileStream.close(); } catch (Exception e) { } } log.debug("Result saved to " + resultOutputFile); } }