Skip to content
Snippets Groups Projects
Select Git revision
  • cda6732070cd3c6a66900ff6dec200f133593daa
  • main default protected
  • 1.8.5
  • 1.8.4
  • 1.8.3
  • 1.8.2
  • 1.8.1
  • 1.8.0
  • 1.7.14
  • 1.7.13
  • 1.7.12
  • 1.7.11
  • 1.7.10
  • 1.7.9
  • 1.7.8
  • 1.7.7
  • 1.7.6
  • 1.7.5
  • 1.7.4
  • 1.7.3
  • 1.7.2
  • 1.7.1
22 results

Cutout.java

Blame
  • ServletCutout.java 16.22 KiB
    
    import java.util.logging.Logger;
    
    import java.security.Principal;
    
    import javax.servlet.ServletException;
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    import javax.servlet.ServletOutputStream;
    
    import java.io.OutputStreamWriter;
    import java.io.IOException;
    import java.io.InputStream;
    import java.io.OutputStream;
    import java.io.PrintWriter;
    
    import java.io.UnsupportedEncodingException;
    import java.net.URLDecoder;
    
    /* for streaming the cutout-file */
    import java.io.File;
    import java.io.FileInputStream;
    import java.io.FileNotFoundException;
    
    import java.util.Arrays;
    import java.util.List;
    import java.util.LinkedList;
    import java.util.Map;
    import java.util.HashMap;
    import java.util.Properties;
    
    // for Logging/Accounting
    import org.json.simple.JSONObject;
    import java.text.SimpleDateFormat;
    import java.util.Date;
    import java.util.TimeZone;
    
    
    import java.nio.file.StandardOpenOption;
    import java.nio.file.Files;
    import java.nio.file.Path;
    import java.nio.file.Paths;
    
    import vo.parameter.*;
    
    public class ServletCutout extends javax.servlet.http.HttpServlet
    {
       protected static final Logger   LOGGER   = Logger.getLogger(ServletCutout.class.getName());
       protected static final Settings settings = Settings.getInstance();
    
       final String RESPONSE_ENCODING = "utf-8";
       final String DEFAULT_RESPONSEFORMAT = settings.defaults.responseFormat;
       final String DEFAULT_SKY_SYSTEM     = settings.defaults.skySystem;
       final String DEFAULT_SPEC_SYSTEM    = settings.defaults.specSystem;
       final String DEFAULT_TIME_SYSTEM = "MJD_UTC"; // FIXME take from confif file
    
       boolean showDuration = settings.defaults.showDuration;
       long startTime_msec;
    
       protected Cutout cutout = new CutoutImpl(settings);
    
       private Subsurvey[] subsurveys = null;
    
       public void init() throws ServletException
       {
          super.init();
    
          LOGGER.info("AMQP : " + settings.amqpConn.toString());
          LOGGER.info("FITS : " + settings.fitsPaths.toString());
          String surveysAbsPathname = settings.fitsPaths.surveysMetadataAbsPathname();
          if( (surveysAbsPathname != null) && (surveysAbsPathname.length() > 1) )
             subsurveys = Subsurvey.loadSubsurveys(surveysAbsPathname);
       }
    
    
       protected void doSodaDescriptor(PrintWriter writer, String requestUrl)
       {
          String theDescriptor =
             "<VOTABLE xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns=\"http://www.ivoa.net/xml/VOTable/v1.3\" version=\"1.3\">"
             + "<RESOURCE type=\"meta\" utype=\"adhoc:service\" name=\"this\">"
             + "<PARAM name=\"standardID\" datatype=\"char\" arraysize=\"*\" value=\"ivo://ivoa.net/std/SODA#sync-1.0\"/>"
             + "<PARAM name=\"accessURL\" datatype=\"char\" arraysize=\"*\" value=\"" + requestUrl  + "\"/>"
             + "<GROUP name=\"inputParams\">"
             +  "<PARAM name=\"ID\" ucd=\"meta.id;meta.dataset\" datatype=\"char\" arraysize=\"*\" value=\"\"/>"
             +  "<PARAM name=\"POS\" ucd=\"pos.outline;obs\" datatype=\"char\" arraysize=\"*\" value=\"\"/>"
             +  "<PARAM name=\"CIRCLE\" ucd=\"phys.angArea;obs\" unit=\"deg\" datatype=\"double\" arraysize=\"3\" xtype=\"circle\" value=\"\"/>"
             +  "<PARAM name=\"POLYGON\" unit=\"deg\" ucd=\"pos.outline;obs\" datatype=\"double\" arraysize=\"*\" xtype=\"polygon\"  value=\"\"/>"
             +  "<PARAM name=\"BAND\" ucd=\"em.wl;stat.interval\" unit=\"m\" datatype=\"double\" arraysize=\"2\" xtype=\"interval\" value=\"\"/>"
             +  "<PARAM name=\"TIME\" ucd=\"time.interval;obs.exposure\" unit=\"d\" datatype=\"double\" arraysize=\"2\" xtype=\"interval\" value=\"\"/>"
             +  "<PARAM name=\"POL\" ucd=\"meta.code;phys.polarization\" datatype=\"char\" arraysize=\"*\" value=\"\"/>"
             +  "<PARAM name=\"RESPONSEFORMAT\" ucd=\"meta.code.mime\" datatype=\"char\" arraysize=\"*\" value=\"application/fits\"/>"
             + "</GROUP>"
             + "</RESOURCE>"
             + "</VOTABLE>";
    
          writer.println(theDescriptor);
       }
    
    
       protected void doCutoutStream(String id, Pos pos, Band band, Time time, Pol pol,
             OutputStream respOutputStream) throws IOException, InterruptedException
       {
          LOGGER.info("trace" + pos);
    
          Resolver rsl = new ResolverFromId();
          rsl.resolve(id);
    
       //   if(pos  != null) pos.setSystem(Pos.System.valueOf(DEFAULT_SKY_SYSTEM));
          if(band != null) band.setSystem(Band.System.valueOf(DEFAULT_SPEC_SYSTEM));
          if(time != null) time.setSystem(Time.System.valueOf(DEFAULT_TIME_SYSTEM));
    
          cutout.doStream(rsl.relPathname(), rsl.hdunum(), pos, band, time, pol, respOutputStream);
       }
    
    
    
       protected DataLink doCutoutFile(String id, Pos pos, Band band, Time time, Pol pol,
             boolean countNullValues, String respFormat)
             throws IOException, InterruptedException
       {
          LOGGER.info("trace");
    
          String relPathname;
          int hdunum;
    
          String dbUri = settings.dbConn.uri();
    
          if(settings.dbConn.isDbUriEmpty())
          {
             Resolver rsl = new ResolverFromId();
             rsl.resolve(id);
             relPathname = rsl.relPathname();
             hdunum      = rsl.hdunum();
          }
          else
          {
             ResolverByObsCore rsl = new ResolverByObsCore(settings.dbConn, subsurveys);
             rsl.resolve(id);
             relPathname = rsl.relPathname();
             hdunum      = rsl.hdunum();
             String subsurveyId = rsl.obsCollection(); //this implementation assumes ObsCore::obs_collection holds ssID
             FitsCard[] extraCards = null;
             if(subsurveyId != null)
             {
                extraCards = Subsurvey.subsurveysFindCards(subsurveys, subsurveyId);
             }
             else
             {
                LOGGER.info("Resolver with Obscore returns subsurveyId null: no extraCards loaded.");
             }
             // FIXME use of extraCards not implemented
          }
    
          final String DEFAULT_TIME_SYSTEM = "MJD_UTC"; // FIXME take from confif file
    
          if(pos  != null) pos.setSystem(Pos.System.valueOf(DEFAULT_SKY_SYSTEM));
          if(band != null) band.setSystem(Band.System.valueOf(DEFAULT_SPEC_SYSTEM));
          if(time != null) time.setSystem(Time.System.valueOf(DEFAULT_TIME_SYSTEM));
    
          CutResult cutResult = cutout.doFile(relPathname, hdunum, pos, band, time, pol, false, null);
    
          DataLink dlk = new DataLink();
    
          dlk.id            = id;
          dlk.accessUrl     = dlk.convertLocalPathnameToRemoteUrl(cutResult.filename,
                settings.fitsPaths.cutouts(), settings.fitsPaths.cutoutsUrl());
          dlk.serviceDef    = null;
          dlk.errorMessage  = null;
          dlk.description   = "A cutout from " + id;// + " by parameters "
                                                    // + pos.toString() + " " + band.toString() + " " + time.toString() + " " + pol.toString();
          dlk.semantics     = "http://www.ivoa.net/rdf/datalink/core#proc#cutout";
          dlk.contentType   = "application/fits";
          dlk.contentLength = cutResult.filesize;
    
          // VLKB-extension to DataLink:
          Coord coord = new Coord(DEFAULT_SKY_SYSTEM, pos, DEFAULT_SPEC_SYSTEM, band, time, pol);
          LOGGER.info(coord.toString());
    
          dlk.inputs         = new Inputs(id, coord, countNullValues);
          dlk.versionString  = Version.asString;
          dlk.cut            = null;
          dlk.absCutPathname = cutResult.filename;
          dlk.datacubeCount  = 1;
          dlk.nullVals       = ((cutResult.nullValueCount.percent < 0) || (cutResult.nullValueCount.totalCount < 1)) ?
             null : cutResult.nullValueCount;
          dlk.mcutResultArr  = null;
    
          return dlk;
       }
    
    
       protected void doMultiValuedParamNotSupported(String message, PrintWriter printWriter)
       {
          printWriter.println("MultiValuedParamNotSupported : " + message);
       }
    
       protected void doUsageError(String message, PrintWriter printWriter)
       {
          printWriter.println("UsageError : " + message);
       }
    
       protected void doError(String message, PrintWriter printWriter)
       {
          printWriter.println("Error : " + message);
       }
    
    
    
       /* HTTP/J2EE -> SODA */
    
    
       /* DALI allows GET and POST for sync services */
    
       protected void doGet(HttpServletRequest request, HttpServletResponse response)
             throws ServletException, IOException, UnsupportedEncodingException
          {
             startTime_msec = System.currentTimeMillis();
    
             final boolean NO_QUERY_STRING = (request.getQueryString() == null);
    
             if(NO_QUERY_STRING)
             {
                writeSodaDescriptor(request, response);
                LOGGER.info("normal exit with SODA service descriptor");
                return;
             }
             else
             {
                convertHttpToSoda(request, response);
                LOGGER.info("normal exit");
             }
          }
    
       protected void doPost(HttpServletRequest request, HttpServletResponse response)
             throws ServletException, IOException, UnsupportedEncodingException
          {
             startTime_msec = System.currentTimeMillis();
    
             final boolean NO_QUERY_STRING = (request.getQueryString() == null);
    
             if(NO_QUERY_STRING)
             {
                writeSodaDescriptor(request, response);
                LOGGER.info("normal exit with SODA service descriptor");
                return;
             }
             else
             {
                convertHttpToSoda(request, response);
                LOGGER.info("normal exit");
             }
          }
    
    
    
       protected void writeSodaDescriptor(HttpServletRequest request, HttpServletResponse response)
             throws ServletException, IOException, UnsupportedEncodingException
          {
             PrintWriter writer = new PrintWriter(new OutputStreamWriter(response.getOutputStream(), RESPONSE_ENCODING));
             response.setContentType("text/xml");
             doSodaDescriptor(writer, request.getRequestURL().toString());
             writer.close();
          }
    
    /*
       private Map<VoParam, String[]> collectSodaParams(HttpServletRequest req)
       {
          Map<VoParam, String[]> params = new HashMap<VoParam, String[]>();
          for(VoParam paramToken : VoParam.values())
          {
             String[] paramValue = req.getParameterValues(paramToken.toString());
             params.put(paramToken, paramValue);
          }
          return params;
       }
    */
    
    
       protected void convertHttpToSoda(HttpServletRequest request, HttpServletResponse response) 
             throws ServletException, IOException, UnsupportedEncodingException
    
          {
             ServletOutputStream  respOutputStream = response.getOutputStream();
    
             try
             {
                /*/Map<SodaParam, String[]> params = collectSodaParams(request);
                SodaParser parser = new SodaParser(params);
    
                String id   = null;
                Pos    pos  = null;
                Band   band = null;
                Time   time = null;
                Pol    pol  = null;
    
                if(parser.sodaReq_hasSodaId())
                {
                   id   = parser.sodaReq_getId();
                   pos  = parser.sodaReq_getPosCirclePolygon();
                   band = parser.sodaReq_getBand();
                   time = parser.sodaReq_getTime();
                   pol  = parser.sodaReq_getPol();
                }
                else
                {
                   id   = parser.vlkbReq_getPubdid();
                   pos  = parser.vlkbReq_getCircleRect();
                   band = parser.vlkbReq_getVelocity();
                }
    */
                Map<String, String[]> params = request.getParameterMap();
    
                String id   = SingleStringParam.parseSingleStringParam(params, "ID");
                Pos    pos  = Pos.parsePos(params, DEFAULT_SKY_SYSTEM);
                Band   band = Band.parseBand(params, DEFAULT_SPEC_SYSTEM);
                Time   time = Time.parseTime(params, DEFAULT_TIME_SYSTEM);
                Pol    pol  = Pol.parsePol(params);
    
    
    
    
    
    
    
                String respFormat = sodaReq_getResponseFormat(request, DEFAULT_RESPONSEFORMAT);
    
                LOGGER.info("responseFormat: " + respFormat);
    
                if(respFormat.equals("application/fits"))
                {
                   response.setContentType(respFormat);
                   doCutoutStream(id, pos, band, time, pol, respOutputStream);
                }
                else if(respFormat.equals("application/x-vlkb+xml"))
                {
                   boolean  countNullValues = vlkbReq_getNullValues(request);
                   response.setContentType(respFormat);
    
                   DataLink respDataLink = doCutoutFile(id, pos, band, time, pol, countNullValues, respFormat);
    
                   /* FIXME errors from engine not checked - cut-file might not have been created */
                   LOGGER.info("DataLink - id:" + respDataLink.id + " url: " + respDataLink.accessUrl );
    
                   final String respEncoding = "utf-8";
                   PrintWriter writer = new PrintWriter(new OutputStreamWriter(respOutputStream, RESPONSE_ENCODING));
                   XmlSerializer.serializeToLegacyCutResults(writer, respEncoding, respDataLink, showDuration, startTime_msec);
                   writer.close(); /* NOTE must close to force flush to complete the xml */
                }
                else
                {
                   throw new IllegalArgumentException("Unsupported RESPONSEFORMAT value : " + respFormat);
                }
    
             }
             catch(MultiValuedParamNotSupported ex)
             {
                LOGGER.info("MultiValuedParamNotSupported: " + ex.getMessage());
    
                response.setStatus(HttpServletResponse.SC_BAD_REQUEST);
                response.setContentType("text/plain");
                PrintWriter writer = new PrintWriter(new OutputStreamWriter(respOutputStream, RESPONSE_ENCODING));
    
                doMultiValuedParamNotSupported(ex.getMessage(), writer);
    
                writer.close();
             }
             catch(IllegalArgumentException ex)
             {
                LOGGER.info("IllegalArgumentException: " + ex.getMessage());
    
                response.setStatus(HttpServletResponse.SC_BAD_REQUEST);
                response.setContentType("text/plain");
                PrintWriter writer = new PrintWriter(new OutputStreamWriter(respOutputStream, RESPONSE_ENCODING));
    
                doUsageError(ex.getMessage(), writer);
    
                writer.close();
             }
             catch(Exception ex)
             {
                LOGGER.info("Exception: " + ex.getMessage());
                ex.printStackTrace();
    
                response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
                response.setContentType("text/plain");
                PrintWriter writer = new PrintWriter(new OutputStreamWriter(respOutputStream, RESPONSE_ENCODING));
    
                doError(ex.toString(), writer);
    
                writer.close();
             }
             finally
             {
                respOutputStream.close();
             }
    
          }
    
    
    
    
    
    
       /* SODA */
    
    
       /* return null if value not present or the value if present exactly once
        * else throw MultiplicityNotSupoorted SODA_error
        */ 
       private String soda_getSingleValue(HttpServletRequest req, String name)
       {
          String[] valArr = req.getParameterValues(name);
    
          if(valArr == null)
             return null;
          else
             if(valArr.length == 0)
                return null;
             else if(valArr.length == 1)
                return valArr[0];
             else
                throw new IllegalArgumentException(
                      "MultiValuedParamNotSupported: " + name + " was found " + valArr.length + " times");
       }
    
    
       private String sodaReq_getResponseFormat(HttpServletRequest req, String defaultResponseFormat)
       {
          String respFormat = soda_getSingleValue(req, "RESPONSEFORMAT");
          return ((respFormat == null) ? defaultResponseFormat : respFormat);
       }
    
    
       private boolean vlkbReq_getNullValues(HttpServletRequest request)
       {
          return (null != soda_getSingleValue(request, "nullvals"));
       }
    
    }
    
    
    
    /* from SODA (upon error):
       Error codes are specified in DALI. Error documents should be text
       using the text/plain content-type and the text must begin with one of the
       following strings:
    
       Error CodeDescription
       ---------------------------------------
    Error: General error (not covered below)
    
    AuthenticationError: Not authenticated
    AuthorizationError: Not authorized to access the resource
    
    ServiceUnavailable: Transient error (could succeed with retry)
    UsageError: Permanent error (retry pointless)
    
    MultiValuedParamNotSupported: request included multiple values for a parameter
    but the service only supports a single value
    */
    
    
    /* from DALI (upon successful request):
       The service should set HTTP headers (Fielding and Gettys et al.,
       1999) that are useful to the correct values where possible. Recommended
       headers to set when possible:
       Content-Type
       Content-Encoding
       Content-Length  -- not in SPDA-stream impossible to know
       Last-Modified   -- not in SODA-stream impossible to know
       */