/* See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * Esri Inc. licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.esri.gpt.control.georss; import com.esri.gpt.catalog.search.OpenSearchProperties; import com.esri.gpt.catalog.search.ResourceLink; import com.esri.gpt.catalog.search.ResourceLinkBuilder; import com.esri.gpt.framework.context.ApplicationConfiguration; import com.esri.gpt.framework.context.ApplicationContext; import com.esri.gpt.framework.geometry.Envelope; import com.esri.gpt.framework.jsf.MessageBroker; import com.esri.gpt.framework.util.Val; import java.io.PrintWriter; import java.text.DateFormat; import java.text.SimpleDateFormat; /** * GEORSS feed writer. */ /* package */ class GeorssFeedWriter implements FeedWriter { // class variables ============================================================= /** update date format */ private static final DateFormat DF = new SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss ZZ"); // instance variables ========================================================== /** Message broker */ private MessageBroker _messageBroker; /** print writer */ private PrintWriter _writer; /** geometry */ private Geometry _geometry = Geometry.esriGeometryPolygon; /** links target */ private RecordSnippetWriter.Target _target = RecordSnippetWriter.Target.blank; /** provider URL */ private String _providerUrl = ""; /** source URL */ private String _sourceUrl = ""; // constructors ================================================================ /** * Creates instance of the writer. * @param messageBroker message broker * @param writer underlying print writer * @param sourceUrl source URL * @param providerUrl provider URL */ public GeorssFeedWriter(MessageBroker messageBroker, PrintWriter writer, String providerUrl, String sourceUrl) { _messageBroker = messageBroker; if (_messageBroker == null) { throw new IllegalArgumentException("A MessageBroker is required."); } _writer = writer; _providerUrl = Val.chkStr(providerUrl); _sourceUrl = Val.chkStr(sourceUrl); } // properties ================================================================== /** * Gets links target. * @return links targets */ public RecordSnippetWriter.Target getTarget() { return _target; } /** * Sets links target. * @param target links target */ public void setTarget(RecordSnippetWriter.Target target) { _target = target; } /** * Gets geometry type. * @return geometry type */ public Geometry getGeometry() { return _geometry; } /** * Sets geometry type. * @param geometry geometry type */ public void setGeometry(Geometry geometry) { _geometry = geometry; } // methods ===================================================================== /** * Writers records. * @param records records to write */ public void write(IFeedRecords records) { String sTitle = _messageBroker.retrieveMessage("catalog.rest.title"); String sDescription = _messageBroker.retrieveMessage("catalog.rest.description"); String sCopyright = _messageBroker.retrieveMessage("catalog.rest.copyright"); String sGenerator = _messageBroker.retrieveMessage("catalog.rest.generator"); if (sTitle.startsWith("???")) sTitle = ""; if (sDescription.startsWith("???")) sDescription = ""; if (sCopyright.startsWith("???")) sCopyright = ""; if (sGenerator.startsWith("???")) sGenerator = ""; // writeTag signature _writer.println("<?xml version=\"1.0\" encoding=\"UTF-8\"?>"); _writer.println("<rss version=\"2.0\""+ " xmlns:georss=\"http://www.georss.org/georss\""+ " xmlns:media=\"http://search.yahoo.com/mrss/\""+ " xmlns:opensearch=\"http://a9.com/-/spec/opensearch/1.1/\""+ " xmlns:atom=\"http://www.w3.org/2005/Atom\""+ " xmlns:geoportal=\"http://www.esri.com/geoportal\"" + ">"); // writeTag channel _writer.println("<channel>"); // writeTag header if (sTitle.length() > 0) { writeTag("title", sTitle); } if (sDescription.length() > 0) { writeTag("description", sDescription); } if (_providerUrl.length()>0) { this.writeTag("link", _providerUrl); } // docs, category, copyright, generator writeTag("docs", "http://www.rssboard.org/rss-specification"); writeTag("category", "GeoRss" ); if (sCopyright.length()>0) { writeTag("copyright", sCopyright); } if (sGenerator.length()>0) { writeTag("generator", sGenerator); } // emails ApplicationContext appCtx = ApplicationContext.getInstance(); ApplicationConfiguration appCfg = appCtx.getConfiguration(); String sEmail = appCfg.getMailConfiguration().getIncomingToAddress(); if (sEmail.length()>0) { writeTag("managingEditor", sEmail); writeTag("webMaster", sEmail); } // add OpenSearch response elements OpenSearchProperties osProps = records.getOpenSearchProperties(); if (osProps != null) { String osTitle = Val.escapeXml(osProps.getShortName()); StringBuffer osQuery = new StringBuffer(); osQuery.append(" role=\"request\""); osQuery.append(" start=\"1\""); osQuery.append(" searchTerms=\"data\""); _writer.println("<atom:link rel=\"search\" type=\"application/opensearchdescription+xml\""+ " href=\""+osProps.getDescriptionURL()+"\" title=\""+osTitle+"\"/>"); _writer.println("<opensearch:totalResults>"+osProps.getNumberOfHits()+"</opensearch:totalResults>"); _writer.println("<opensearch:startIndex>"+osProps.getStartRecord()+"</opensearch:startIndex>"); _writer.println("<opensearch:itemsPerPage>"+osProps.getRecordsPerPage()+"</opensearch:itemsPerPage>"); //_writer.println("<opensearch:Query "+osQuery.toString()+"/>"); //<opensearch:Query role="request" searchTerms="New York History" startPage="1" /> } // write Atom 'self' link if (_sourceUrl.length()>0) { _writer.println("<atom:link href=\"" +Val.escapeXml(_sourceUrl)+ "\" rel=\"self\" type=\"application/rss+xml\" />"); } // writeTag items RecordSnippetWriter snippetWriter = new RecordSnippetWriter(_messageBroker, _writer); snippetWriter.setTarget(_target); for (IFeedRecord record : records) { writeRecord(snippetWriter, record, sTitle); } // complete data _writer.println("</channel>"); _writer.println("</rss>"); } /** * Writes a single record. * @param snippetWriter description HTML snippet writer * @param record records to writeTag * @param sSourceTitle source title */ private void writeRecord( RecordSnippetWriter snippetWriter, IFeedRecord record, String sSourceTitle) { _writer.println("<item>"); // link String sMetadataLink = record.getResourceLinks().findUrlByTag(ResourceLink.TAG_METADATA); String sEncodedLink = Val.escapeXml(sMetadataLink); // guid if (sEncodedLink.length() > 0) { writeTag("link", sMetadataLink); _writer.print("<guid isPermaLink=\"true\">"); _writer.print(sEncodedLink); _writer.println("</guid>"); } // title String sTitle = record.getTitle(); if (sTitle.length() == 0) { sTitle = record.getUuid(); } writeTag("title", sTitle); // pub date if (record.getModfiedDate()!=null) { writeTag("pubDate", DF.format(record.getModfiedDate())); } // source if (_sourceUrl.length()>0) { _writer.print("<source url=\""); _writer.print(Val.escapeXml(_sourceUrl)); _writer.print("\">"); _writer.print(Val.escapeXml(sSourceTitle)); _writer.println("</source>"); } // description _writer.println("<description><![CDATA["); snippetWriter.write(record); _writer.println("]]></description>"); // content type (category) if (record.getContentType().length() > 0) { writeTag("category", record.getContentType()); } // thumbnail (media) String url = Val.chkUrl(record.getResourceLinks().getThumbnail().getUrl()); if (url.length() > 0) { _writer.print("<media:content url=\""); _writer.print(Val.escapeXml(url)); _writer.println("\"/>"); writeTag("media:text", sTitle); } // record type thumbnail ResourceLink contentTypeLink = record.getResourceLinks().findByTag(ResourceLink.TAG_CONTENTTYPE); String recordTypeThumbnail = Val.chkUrl(contentTypeLink!=null? contentTypeLink.getUrl(): ""); if (url.length()>0 || recordTypeThumbnail.length() > 0) { _writer.print("<media:thumbnail url=\""); _writer.print(Val.escapeXml(url.length()>0? url: recordTypeThumbnail)); _writer.println("\"/>"); } // write geometry writeGeometry(record); // resource URL ResourceLink openRL = record.getResourceLinks().findByTag(ResourceLink.TAG_OPEN); if (openRL!=null) { String serviceType = Val.chkStr(openRL.getParameters().getValue(ResourceLinkBuilder.RESOURCE_TYPE)); _writer.print("<geoportal:resourceUrl"); if (serviceType.length()>0) { _writer.print(" " +ResourceLinkBuilder.RESOURCE_TYPE+ "=\""); _writer.print(Val.escapeXml(serviceType)); _writer.print("\""); } _writer.print(">"); _writer.print(Val.escapeXml(openRL.getUrl())); _writer.println("</geoportal:resourceUrl>"); } _writer.println("</item>"); _writer.flush(); } /** * Writes geometry. * @param envelope envelope */ private void writeGeometry(IFeedRecord record) { if (record.getEnvelope()!=null && record.getEnvelope().isValid()) { switch (getGeometry()) { case esriGeometryPoint: writePoint(record.getEnvelope()); break; default: case esriGeometryPolygon: writePolygon(record.getEnvelope()); break; case esriGeometryEnvelope: writeBox(record.getEnvelope()); break; } } } /** * Writes simple attribute. * @param name attribute name * @param value attribute value */ private void writeTag(String name, String value) { _writer.print("<" + name + ">"); _writer.print(Val.escapeXml(value)); _writer.println("</" + name + ">"); } /** * Writes geometry as esriGeometryPoint. * @param envelope envelope */ private void writePoint(Envelope envelope) { _writer.print("<georss:point>"); _writer.print(getValidCenterY(envelope) + " " + getValidCenterX(envelope)); _writer.println("</georss:point>"); } /** * Writes geometry as esriGeometryPolygon. * @param envelope envelope */ private void writePolygon(Envelope envelope) { _writer.print("<georss:polygon>"); _writer.print(getValidMaxY(envelope) + " " + envelope.getMinX()); _writer.print(" "); _writer.print(getValidMaxY(envelope) + " " + envelope.getMaxX()); _writer.print(" "); _writer.print(getValidMinY(envelope) + " " + envelope.getMaxX()); _writer.print(" "); _writer.print(getValidMinY(envelope) + " " + envelope.getMinX()); _writer.print(" "); _writer.print(getValidMaxY(envelope) + " " + envelope.getMinX()); _writer.println("</georss:polygon>"); } /** * Writes geometry as esriGeometryPolygon. * @param envelope envelope */ private void writeBox(Envelope envelope) { _writer.print("<georss:box>"); _writer.print(getValidMinY(envelope) + " " + envelope.getMinX()); _writer.print(" "); _writer.print(getValidMaxY(envelope) + " " + envelope.getMaxX()); _writer.println("</georss:box>"); } /** * Gets valid center X. * @return valid center X */ private double getValidCenterX(Envelope envelope) { return envelope.getCenterX(); } /** * Gets valid center Y * @return valid center Y */ private double getValidCenterY(Envelope envelope) { return Math.min(+90.0, Math.max(-90.0, envelope.getCenterY())); } /** * Gets valid min Y. * @return valid min Y */ private double getValidMinY(Envelope envelope) { return Math.min(+90.0, Math.max(-90.0, envelope.getMinY())); } /** * Gets valid max Y * @return valid max Y */ private double getValidMaxY(Envelope envelope) { return Math.min(+90.0, Math.max(-90.0, envelope.getMaxY())); } // enums ======================================================================= /** * Geometry */ public enum Geometry { /** esriGeometryPoint */ esriGeometryPoint, /** esriGeometryPolygon */ esriGeometryPolygon, /** esriGeometryEnvelope */ esriGeometryEnvelope, /** lattitude, longitude */ spatial; /** * Checks value given as string. * @param value value given as string * @return geometry reprsented by the string or {@link Geometry#esriGeometryPolygon} if * geometry not recognized */ public static Geometry checkValueOf(String value) { value = Val.chkStr(value); for (Geometry g : values()) { if (g.name().equalsIgnoreCase(value)) { return g; } } return esriGeometryPolygon; } } }