001    /*
002     * $Id: SuomiNPPProductProfile.java,v 1.2 2012/02/19 17:35:42 davep Exp $
003     *
004     * This file is part of McIDAS-V
005     *
006     * Copyright 2007-2012
007     * Space Science and Engineering Center (SSEC)
008     * University of Wisconsin - Madison
009     * 1225 W. Dayton Street, Madison, WI 53706, USA
010     * https://www.ssec.wisc.edu/mcidas
011     * 
012     * All Rights Reserved
013     * 
014     * McIDAS-V is built on Unidata's IDV and SSEC's VisAD libraries, and
015     * some McIDAS-V source code is based on IDV and VisAD source code.  
016     * 
017     * McIDAS-V is free software; you can redistribute it and/or modify
018     * it under the terms of the GNU Lesser Public License as published by
019     * the Free Software Foundation; either version 3 of the License, or
020     * (at your option) any later version.
021     * 
022     * McIDAS-V is distributed in the hope that it will be useful,
023     * but WITHOUT ANY WARRANTY; without even the implied warranty of
024     * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
025     * GNU Lesser Public License for more details.
026     * 
027     * You should have received a copy of the GNU Lesser Public License
028     * along with this program.  If not, see http://www.gnu.org/licenses.
029     */
030    
031    package edu.wisc.ssec.mcidasv.data.hydra;
032    
033    import java.io.BufferedReader;
034    import java.io.IOException;
035    import java.io.InputStream;
036    import java.io.InputStreamReader;
037    import java.io.StringReader;
038    import java.io.UnsupportedEncodingException;
039    import java.net.URLDecoder;
040    import java.util.ArrayList;
041    import java.util.Enumeration;
042    import java.util.HashMap;
043    import java.util.jar.JarEntry;
044    import java.util.jar.JarFile;
045    
046    import javax.xml.parsers.DocumentBuilder;
047    import javax.xml.parsers.DocumentBuilderFactory;
048    import javax.xml.parsers.ParserConfigurationException;
049    
050    import org.slf4j.Logger;
051    import org.slf4j.LoggerFactory;
052    
053    import org.w3c.dom.Document;
054    import org.w3c.dom.Node;
055    import org.w3c.dom.NodeList;
056    
057    import org.xml.sax.EntityResolver;
058    import org.xml.sax.InputSource;
059    import org.xml.sax.SAXException;
060    
061    public class SuomiNPPProductProfile {
062            
063            private static final Logger logger = LoggerFactory.getLogger(SuomiNPPProductProfile.class);
064            
065            DocumentBuilder db = null;
066            // if we need to pull product profiles from the McV jar file
067            boolean readFromJar = false;
068            HashMap<String, String> rangeMin = new HashMap<String, String>();
069            HashMap<String, String> rangeMax = new HashMap<String, String>();
070            HashMap<String, String> scaleFactorName = new HashMap<String, String>();
071            HashMap<String, ArrayList<Float>> fillValues = new HashMap<String, ArrayList<Float>>();
072    
073            public SuomiNPPProductProfile() throws ParserConfigurationException, SAXException, IOException {
074    
075            logger.trace("SuomiNPPProductProfile init...");
076                    DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
077            factory.setNamespaceAware(false);
078            db = factory.newDocumentBuilder();
079            db.setEntityResolver(new EntityResolver()
080            {
081                public InputSource resolveEntity(String publicId, String systemId)
082                    throws SAXException, IOException
083                {
084                    return new InputSource(new StringReader(""));
085                }
086            });
087    
088            }
089            
090            /**
091             * See if for a given N_Collection_Short_Name attribute, the profile is present
092             * @param pathStr the directory the XML Product Profiles reside
093             * @param attrName The attribute name our file should match
094             * @return the full file name for the XML Product Profile
095             */
096            
097            public String getProfileFileName(String attrName) {
098                    // sanity check
099                    if (attrName == null) return null;
100                    
101                    // print top level classloader files
102                    // this is how we will tell if we need to pull the profiles out of a jar file
103                    
104                    readFromJar = false;
105            ClassLoader loader = getClass().getClassLoader();
106            InputStream in = loader.getResourceAsStream(".");
107            BufferedReader rdr = new BufferedReader(new InputStreamReader(in));
108            String l;
109            try {
110                            while ((l = rdr.readLine()) != null) {
111                                if (l.equals("mcidasv.jar")) {
112                                    readFromJar = true;
113                                }
114                            }
115                            rdr.close();
116                    } catch (IOException e) {
117                            e.printStackTrace();
118                            return null;
119                    }
120    
121                    // we need to pull the XML Product Profiles out of mcidasv.jar
122                    if (readFromJar) {
123                            JarFile jar;
124                            try {
125                                    jar = new JarFile(URLDecoder.decode("mcidasv.jar", "UTF-8"));
126                                    Enumeration<JarEntry> entries = jar.entries(); //gives ALL entries in jar
127                                    boolean found = false;
128                                    String name = null;
129                                    while (entries.hasMoreElements()) {
130                                            name = entries.nextElement().getName();
131                                            if (name.contains("XML_Product_Profiles")) { // filter according to the profiles
132                                                    logger.trace("looking at line: " + name);
133                                                    if (name.contains(attrName + "-PP")) {
134                                                            found = true;
135                                                            break;
136                                                    }
137                                            }
138                                    }
139                                    if (found == true) {
140                                            logger.trace("Found profile: " + name);
141                                            return name;
142                                    }
143                            } catch (UnsupportedEncodingException e) {
144                                    e.printStackTrace();
145                                    return null;
146                            } catch (IOException e) {
147                                    e.printStackTrace();
148                                    return null;
149                            }
150                    } else {
151                            // read contents of XML Product Profile directory as stream
152                            InputStream ios = getClass().getResourceAsStream("resources/NPP/XML_Product_Profiles/");
153                            BufferedReader dirReader = new BufferedReader(new InputStreamReader(ios));
154                            try {
155                                    String line = dirReader.readLine();
156                                    boolean found = false;
157                                    while (line != null) {
158                                            logger.trace("looking at line: " + line);
159                                            if (line.contains(attrName + "-PP")) {
160                                                    found = true;
161                                                    break;
162                                            }
163                                            line = dirReader.readLine();
164                                    }
165                                    ios.close();
166                                    if (found == true) {
167                                            logger.trace("Found profile: " + attrName);
168                                            return line;
169                                    }
170                            } catch (IOException ioe) {
171                                    ioe.printStackTrace();
172                                    return null;
173                            }
174                    }
175    
176                    return null;
177            }
178            
179            public void addMetaDataFromFile(String fileName) throws SAXException, IOException {
180                    logger.trace("Attempting to parse XML Product Profile: " + fileName);
181                    Document d = null;
182                    InputStream ios = null;
183                    if (readFromJar) {
184                            JarFile jar = new JarFile(URLDecoder.decode("mcidasv.jar", "UTF-8"));
185                            JarEntry je = jar.getJarEntry(fileName);
186                            ios = jar.getInputStream(je);
187                            d = db.parse(ios);
188                    } else {
189                            ios = getClass().getResourceAsStream("resources/NPP/XML_Product_Profiles/" + fileName);
190                            d = db.parse(ios);
191                    }
192                    NodeList nl = d.getElementsByTagName("Field");
193                    for (int i = 0; i < nl.getLength(); i++) {
194                            ArrayList<Float> fValAL = new ArrayList<Float>();
195                            Node n = nl.item(i);
196                            NodeList children = n.getChildNodes();
197                            NodeList datum = null;
198                            String name = null;
199                            
200                            // cycle through once, finding name and datum node
201                            for (int j = 0; j < children.getLength(); j++) {
202                                    Node child = children.item(j);
203                                    logger.trace("looking at node name: " + child.getNodeName());
204                                    if (child.getNodeName().equals("Name")) {
205                                            name = child.getTextContent();
206                                            logger.trace("Found Suomi NPP product name: " + name);
207                                    }
208                                    if (child.getNodeName().equals("Datum")) {
209                                            datum = child.getChildNodes();
210                                            logger.trace("Found Datum node");
211                                    }
212                            }
213                            
214                            String rMin = null;
215                            String rMax = null;             
216                            String sFactorName = null;      
217    
218                            if ((name != null) && (datum != null)) {
219                                    for (int j = 0; j < datum.getLength(); j++) {
220                                            Node child = datum.item(j);
221                                            if (child.getNodeName().equals("RangeMin")) {
222                                                    rMin = child.getTextContent();
223                                            }
224                                            if (child.getNodeName().equals("RangeMax")) {
225                                                    rMax = child.getTextContent();
226                                            }
227                                            if (child.getNodeName().equals("ScaleFactorName")) {
228                                                    sFactorName = child.getTextContent();
229                                            }
230                                            if (child.getNodeName().equals("FillValue")) {
231                                                    // go one level further to child element Value
232                                                    NodeList grandChildren = child.getChildNodes();
233                                                    for (int k = 0; k < grandChildren.getLength(); k++) {
234                                                            Node grandChild = grandChildren.item(k);
235                                                            if (grandChild.getNodeName().equals("Value")) {
236                                                                    String fillValueStr = grandChild.getTextContent();
237                                                                    fValAL.add(new Float(Float.parseFloat(fillValueStr)));
238                                                            }
239                                                    }
240                                            }
241                                    }
242                            }
243                            
244                            if ((name != null) && (rMin != null)) {
245                                    logger.trace("Adding range min: " + rMin + " for product: " + name);
246                                    rangeMin.put(name, rMin);
247                            }
248                            
249                            if ((name != null) && (rMax != null)) {
250                                    logger.trace("Adding range max: " + rMax + " for product: " + name);
251                                    rangeMax.put(name, rMax);
252                            }
253                            
254                            if ((name != null) && (sFactorName != null)) {
255                                    logger.trace("Adding scale factor name: " + sFactorName + " for product: " + name);
256                                    scaleFactorName.put(name, sFactorName);
257                            }
258                            
259                            if ((name != null) && (! fValAL.isEmpty())) {
260                                    logger.trace("Adding fill value array for product: " + name);
261                                    fillValues.put(name, fValAL);
262                            }
263                            
264                    }
265                    if (ios != null) {
266                            try {
267                                    ios.close();
268                            } catch (IOException ioe) {
269                                    // do nothing
270                            }
271                    }
272            }
273    
274            /**
275             * Check if this product profile has a product AND metadata
276             * Only need to check one of the possible fields
277             * @param product name
278             * @return true if both conditions met
279             */
280            
281            public boolean hasNameAndMetaData(String name) {
282                    if (rangeMin.containsKey(name)) {
283                            return true;
284                    } else {
285                            return false;
286                    }
287            }
288            
289            public String getRangeMin(String name) {
290                    return rangeMin.get(name);
291            }
292            
293            public String getRangeMax(String name) {
294                    return rangeMax.get(name);
295            }
296            
297            public String getScaleFactorName(String name) {
298                    return scaleFactorName.get(name);
299            }
300            
301            public ArrayList<Float> getFillValues(String name) {
302                    return fillValues.get(name);
303            }
304    
305    }