V1_0.java [src/java/m/rv/soilprops] Revision: default Date:
/*
* $Id$
*
* This file is part of the Cloud Services Integration Platform (CSIP),
* a Model-as-a-Service framework, API, and application suite.
*
* 2012-2022, OMSLab, Colorado State University.
*
* OMSLab licenses this file to you under the MIT license.
* See the LICENSE file in the project root for more information.
*/
package m.rv.soilprops;
import csip.ModelDataService;
import csip.api.server.ServiceException;
import csip.SessionLogger;
import csip.annotations.Description;
import csip.annotations.Name;
import csip.annotations.Resource;
import csip.annotations.VersionInfo;
import csip.utils.JSONUtils;
import csip.utils.Parallel;
import csip.utils.Parallel.Run;
import edit.EditConnection;
import edit.EditQueries;
import edit.Utils;
import gisobjects.GISObject;
import static gisobjects.GISObject.DEFAULT_ASSUMED_SRID;
import gisobjects.GISObjectException;
import gisobjects.GISObjectFactory;
import gisobjects.db.GISEngine;
import gisobjects.db.GISEngineFactory;
import java.io.IOException;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import javax.ws.rs.Path;
import m.rv.ApplicationResources;
import static m.rv.ApplicationResources.GIS_DB;
import static m.rv.ApplicationResources.SOILS_SOURCE;
import org.codehaus.jettison.json.JSONArray;
import org.codehaus.jettison.json.JSONException;
import org.codehaus.jettison.json.JSONObject;
import soils.Coecoclass;
import soils.Component;
import soils.MapUnit;
import soils.SoilsData;
import soils.db.SOILS_DATA;
import soils.db.SOILS_DB_Factory;
import soils.db.tables.TableCoecoclass;
import soils.db.tables.TableCoecoclassCalculations;
import soils.db.tables.TableComponent;
import soils.db.tables.TableComponentCalculations;
import soils.db.tables.TableHorizon;
import soils.db.tables.TableHorizonCalculations;
import soils.db.tables.TableMapUnit;
import soils.db.tables.TableMapUnitCalculations;
import soils.db.tables.TableTextureGroup;
/**
*
* @author <a href="mailto:shaun.case@colostate.edu">Shaun Case</a>
*/
@Name("Get Soil Map Unit and Component Properties")
@Description("Get and return a payload of Soil Data Mart (SDM) soil properties "
+ "and Ecosystem Dynamics Interpretative Tool (EDIT) ecological site properties.")
@VersionInfo("1.0")
@Path("d/edit_soils_properties/1.0")
@Resource(from = ApplicationResources.class)
@Resource(from = soils.db.DBResources.class)
public class V1_0 extends ModelDataService {
static final String AOA_GEOMETRY = "aoa_geometry";
@Override
protected void doProcess() throws Exception {
JSONObject aoa_geometry = parameter().getParamJSON(AOA_GEOMETRY);
try (GISEngine gisEngine = GISEngineFactory.createGISEngine(resources().getJDBC(GIS_DB)); SOILS_DATA soilsDb = SOILS_DB_Factory.createEngine(V1_0.class, LOG, SOILS_SOURCE)) {
GISObject aoaGeometry = GISObjectFactory.createGISObject(aoa_geometry, gisEngine);
AoA aoa = new AoA(soilsDb, aoaGeometry, LOG);
aoa.findSoils();
results().put("aoa_acres", aoa.getArea());
results().put("mapunits", aoa.toJSON());
}
}
static class AoA extends soils.AoA {
static final int ALLOWED_SRID = DEFAULT_ASSUMED_SRID;
static final double DEFAULT_POINT_BUFFER_SIZE = 113.5; // 133.5m buffer = 10 acres.
/**
*
* @param soilsDb
* @param aoa_geometry
* @param Log
* @throws GISObjectException
* @throws SQLException
* @throws JSONException
* @throws IOException
* @throws ServiceException
*/
AoA(SOILS_DATA soilsDb, GISObject aoa_geometry, SessionLogger Log) throws Exception {
super(soilsDb, aoa_geometry, Log);
if (getSRID() != ALLOWED_SRID)
throw new ServiceException("Invalid SRID: " + getSRID() + " (only WGS-84 (4326 SRID) is supported.");
shape.makeValid(GISObject.UsePurpose.all_purposes, GISObject.GISType.all_types);
if (shape.getGeometry().getGeometryType().equals("Point"))
shape = shape.buffer(DEFAULT_POINT_BUFFER_SIZE);
area = shape.areaInAcres();
if (area > 10000.0)
throw new ServiceException("Feature area greater than 10,000 acres! This is too large.");
}
/**
*
* @throws SQLException
* @throws ServiceException
* @throws GISObjectException
*/
public void findSoils() throws Exception {
if (shape != null)
findIntersectedMapUnitsWithAreasAndShapes();
else
throw new ServiceException("No AoI location was speified. Please specify an AoI location as a geometry.");
if (soilsDb.findAllBasicComponentHorizonFragTextureData(map_units, true)) {
soilsDb.findEcoClassForMukeyList(map_units,
" ((ecoclassid LIKE 'R%' AND ecoclasstypename='NRCS Rangeland Site') "
+ " OR (ecoclassid LIKE 'F%' AND ecoclasstypename='NRCS Forestland Site'))");
getEDITEcoclassNames();
}
}
private void queryEdit(Coecoclass coEcoClass, EditConnection editConn) throws Exception {
String ecId = coEcoClass.ecoclassid();
// synonym handling
ecId = EditQueries.getSynonymFor(editConn.fetchAllSynonyms(), ecId);
coEcoClass.setEDITPath(EditQueries.getSiteDescrUrl(ecId));
String edit_es_name = EditQueries.getEcoClassNameFor(editConn.fetchEcoClassList(ecId), ecId);
if ((edit_es_name != null) && (!edit_es_name.isEmpty())) {
coEcoClass.ecoclassname(edit_es_name);
}
}
private void getEDITEcoclassNames() throws Exception {
if (map_units != null) {
List<Run> runs = new ArrayList<>();
EditConnection editConn = new EditConnection(LOG);
for (MapUnit mapUnit : map_units.values()) {
for (Component component : mapUnit.components().values()) {
for (Coecoclass coEcoClass : component.ecoClasses().values()) {
if (Utils.isEcoclassId(coEcoClass.ecoclassid()))
runs.add(() -> queryEdit(coEcoClass, editConn));
}
}
}
if (!runs.isEmpty())
Parallel.run(runs);
} else
throw new ServiceException("Cannot find ecoclass names from EDIT with an empty mapunit list.");
}
/**
*
* @return
*/
public final int getSRID() {
return shape.getGeometry().getSRID();
}
/**
*
* @return @throws JSONException
*/
public JSONArray toJSON() throws Exception {
JSONArray mapunitData = new JSONArray();
for (MapUnit mapUnit : map_units.values()) {
if (!mapUnit.isExcluded()) {
List<GISObject> intersections = mapUnit.getIntersectionPolygons();
mapUnit.setOutputColumnOrdering(Arrays.asList(
TableMapUnit.AREASYMBOL_NAME, TableMapUnit.AREA_NAME, TableMapUnit.MUKEY, TableMapUnit.MUNAME,
TableMapUnit.MUSYM, TableMapUnit.MUACRES, TableMapUnitCalculations.AREA_NAME, TableMapUnitCalculations.AREA_PCT
));
JSONArray mapUnitArray = new JSONArray();
mapUnit.mapUnitJSON(mapUnitArray);
JSONArray intersectionArray = new JSONArray();
for (GISObject intersect : intersections) {
intersectionArray.put(intersect.toJSON());
}
mapUnitArray.put(JSONUtils.data("mapunit_intersections", intersectionArray));
JSONArray componentArray = new JSONArray();
for (Component component : mapUnit.components().values()) {
if (!component.isExcluded()) {
component.setOutputColumnOrdering(Arrays.asList(
TableComponent.COKEY, TableComponent.COMPNAME, TableComponent.COMPPCT_R_NAME,
TableComponent.MAJ_COMP_FLAG, TableComponentCalculations.AREA_PCT_NAME, TableComponentCalculations.COMP_AREA_NAME
));
component.setHorizonOutputColumnOrdering(Arrays.asList(TableHorizon.CHKEY_NAME, TableHorizonCalculations.DEPT_R_IN,
TableHorizonCalculations.DEPB_R_IN));
component.setTextureGroupOutputColumnOrdering(Arrays.asList(TableTextureGroup.DESCRIPTION));
JSONArray componentObject = component.toJSON(false);
JSONArray ecoClassArray = new JSONArray();
for (Coecoclass ecoClass : component.ecoClasses().values()) {
ecoClass.setOutputColumns(Arrays.asList(TableCoecoclass.ECOCLASSID,
TableCoecoclass.ECOCLASSNAME, TableCoecoclassCalculations.ES_EDIT_URL));
ecoClassArray.put(ecoClass.toJSON());
}
componentObject.put(JSONUtils.data("EcoClassList", ecoClassArray));
componentArray.put(componentObject);
}
}
if (componentArray.length() > 0) {
mapUnitArray.put(JSONUtils.data(SoilsData.MAPUNIT_COMPONENT_LIST_NAME, componentArray));
mapunitData.put(mapUnitArray);
}
}
}
return mapunitData;
}
}
}