package org.openforis.collect.earth.app.server; import static org.openforis.collect.earth.app.EarthConstants.PLACEMARK_ID_PARAMETER; import java.io.IOException; import java.io.UnsupportedEncodingException; import java.net.URLDecoder; import java.util.ArrayList; import java.util.HashMap; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import java.util.Map.Entry; import java.util.NavigableMap; import java.util.Set; import java.util.SortedMap; import java.util.TreeMap; import javax.servlet.http.HttpServletResponse; import org.openforis.collect.earth.app.EarthConstants; import org.openforis.collect.earth.app.service.AbstractEarthSurveyService; import org.openforis.collect.earth.app.view.Messages; import org.openforis.collect.earth.core.handlers.BalloonInputFieldsUtils; import org.openforis.collect.earth.core.model.PlacemarkLoadResult; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.bind.annotation.RequestParam; /** * Controller to load and store the information that is stored in Collect Earth for one placemark (plot) * * @author Alfonso Sanchez-Paus Diaz * @author S. Ricci * */ public class AbstractPlacemarkDataController extends JsonPocessorServlet { private static final String PREVIEW_PLOT_ID = "$[EXTRA_id]"; private Object lastPlacemarkId; private String lastPlacemarkStep; @Autowired AbstractEarthSurveyService earthSurveyService; protected void placemarkInfoExpanded(@RequestParam("id") String placemarkId, HttpServletResponse response) throws IOException { PlacemarkLoadResult result; if (placemarkId == null || placemarkId.equals(PREVIEW_PLOT_ID)) { result = handleEmptyPlot(); } else { placemarkId = replacePlacemarkIdTestValue(placemarkId); result = getDataAccessor().loadDataExpanded(placemarkId.split(",")); if (result.isSuccess()) { result.setMessage("The placemark was found"); if (placemarkId.equals(lastPlacemarkId)) { result.setCurrentStep(lastPlacemarkStep); } } else { getLogger().info("No placemark found with id: {%s}", placemarkId); } } setJsonResponse(response, result); } private PlacemarkLoadResult handleEmptyPlot() { PlacemarkLoadResult result; result = new PlacemarkLoadResult(); result.setSuccess(false); String errorMessage = "No placemark ID found in the received request"; result.setMessage(errorMessage); getLogger().error(errorMessage); //$NON-NLS-1$ return result; } @RequestMapping(value="/save-data-expanded", method = RequestMethod.POST) public void saveDataExpanded(PlacemarkUpdateRequest updateRequest, HttpServletResponse response) throws IOException { Map<String, String> collectedData = adjustParameters(updateRequest); PlacemarkLoadResult result; if (collectedData.isEmpty()) { result = handleEmptyCollectedData(); } else { String placemarkId = replacePlacemarkIdTestValue(updateRequest.getPlacemarkId()); result = processCollectedData(updateRequest, collectedData, placemarkId); } setJsonResponse(response, result); } public PlacemarkLoadResult processCollectedData( PlacemarkUpdateRequest updateRequest, Map<String, String> collectedData, String placemarkKey ) { PlacemarkLoadResult result = getDataAccessor().updateData( placemarkKey.split(",") , collectedData, updateRequest.isPartialUpdate()); if (result.isSuccess()) { result.setMessage(Messages.getString("SaveEarthDataServlet.2")); //$NON-NLS-1$ lastPlacemarkId = placemarkKey; lastPlacemarkStep = updateRequest.getCurrentStep(); }else{ logger.warn("Error when saving the data %s", result ); } return result; } public PlacemarkLoadResult handleEmptyCollectedData() { PlacemarkLoadResult result; result = new PlacemarkLoadResult(); result.setSuccess(false); result.setMessage(Messages.getString("SaveEarthDataServlet.0")); //$NON-NLS-1$ getLogger().info("The request was empty"); //$NON-NLS-1$ return result; } private Map<String, String> adjustParameters( PlacemarkUpdateRequest updateRequest ) throws UnsupportedEncodingException { Map<String, String> originalCollectedData = updateRequest.getValues(); Map<String, String> result = new HashMap<String, String>(originalCollectedData.size()); for (Entry<String, String> entry : originalCollectedData.entrySet()) { if( entry.getKey().equals( EarthConstants.PLACEMARK_ID_PARAMETER ) ){ // If there are multiple keys this value will be the combination of the keys, with the first value actually containing the plot id entry.setValue( entry.getValue().split(",")[0]); } //decode parameter name, it was previously encoded by the client result.put(URLDecoder.decode(entry.getKey(), "UTF-8"), entry.getValue()); } replaceTestParameters(result); return sortParameters(result); } /** * Sort parameters based on schema order (BFS) * @param parameters Parameters to be sorted * @return The parameters sorted alphabetically */ public Map<String, String> sortParameters(Map<String, String> parameters) { NavigableMap<String, String> navigableParameters = new TreeMap<String, String>(parameters); //extract parameter names in order BalloonInputFieldsUtils collectParametersHandler = new BalloonInputFieldsUtils(); Map<String, String> sortedParameterNameByNodePath = collectParametersHandler.getHtmlParameterNameByNodePath(earthSurveyService.getRootEntityDefinition()); List<String> sortedParameterNames = new ArrayList<String>(sortedParameterNameByNodePath.values()); //create a new map and put the parameters in order there Map<String, String> result = new LinkedHashMap<String, String>(navigableParameters.size()); for (String parameterName : sortedParameterNames) { //get all the entries with key starting with parameterName SortedMap<String,String> subMap = new TreeMap<String, String>( navigableParameters.subMap(parameterName, parameterName + Character.MAX_VALUE) ); Set<Entry<String,String>> entrySet = subMap.entrySet(); for (Entry<String, String> entry : entrySet) { result.put(entry.getKey(), entry.getValue()); navigableParameters.remove(entry.getKey()); } } //add remaining parameters (if any) result.putAll(navigableParameters); return result; } /** * This method replaces the variable values that the form contains when it is not run * through Google Earth and the variable replacement of the ExtendedData of the KML does not kick in. * * @param parameterByName * The data POSTed by the form that has already been processed. */ private void replaceTestParameters(Map<String, String> parameterByName) { // REMOVE THIS!!!! replaceParameter(parameterByName, PLACEMARK_ID_PARAMETER, "$[id]", "testPlacemark"); //$NON-NLS-1$ //$NON-NLS-2$ replaceParameter(parameterByName, "collect_integer_elevation", "$[elevation]", "0"); //$NON-NLS-1$ //$NON-NLS-2$ replaceParameter(parameterByName, "collect_real_slope", "$[slope]", "0"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ replaceParameter(parameterByName, "collect_real_aspect", "$[aspect]", "0"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ replaceParameter(parameterByName, "collect_coord_location", "$[latitude],$[longitude]", "0,0"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ } private void replaceParameter(Map<String, String> parameterByName, String name, String searchValue, String replaceValue) { String val = parameterByName.get(name); if (searchValue.equals(val)) { parameterByName.put(name, replaceValue); } } private String replacePlacemarkIdTestValue(String placemarkId) { if (placemarkId.equals("$[id]")) //$NON-NLS-1$ return "testPlacemark"; //$NON-NLS-1$ else return placemarkId; } }