001/*
002 * This file is part of McIDAS-V
003 *
004 * Copyright 2007-2024
005 * Space Science and Engineering Center (SSEC)
006 * University of Wisconsin - Madison
007 * 1225 W. Dayton Street, Madison, WI 53706, USA
008 * https://www.ssec.wisc.edu/mcidas/
009 * 
010 * All Rights Reserved
011 * 
012 * McIDAS-V is built on Unidata's IDV and SSEC's VisAD libraries, and
013 * some McIDAS-V source code is based on IDV and VisAD source code.  
014 * 
015 * McIDAS-V is free software; you can redistribute it and/or modify
016 * it under the terms of the GNU Lesser Public License as published by
017 * the Free Software Foundation; either version 3 of the License, or
018 * (at your option) any later version.
019 * 
020 * McIDAS-V is distributed in the hope that it will be useful,
021 * but WITHOUT ANY WARRANTY; without even the implied warranty of
022 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
023 * GNU Lesser Public License for more details.
024 * 
025 * You should have received a copy of the GNU Lesser Public License
026 * along with this program.  If not, see https://www.gnu.org/licenses/.
027 */
028package edu.wisc.ssec.mcidasv.util;
029
030import java.io.IOException;
031import java.net.UnknownHostException;
032
033import edu.wisc.ssec.mcidas.AreaDirectoryList;
034import edu.wisc.ssec.mcidas.AreaFileException;
035import edu.wisc.ssec.mcidas.adde.AddeException;
036
037import org.slf4j.Logger;
038import org.slf4j.LoggerFactory;
039import visad.VisADException;
040import visad.data.mcidas.AreaAdapter;
041
042/**
043 * {@code ErrorCodeAreaUtils} sole purpose is to allow McIDAS-V to associate
044 * the error codes in
045 * {@link edu.wisc.ssec.mcidas.adde.AddeException AddeException} with any
046 * exceptions generated by {@link visad.data.mcidas.AreaAdapter AreaAdapter} or
047 * {@link edu.wisc.ssec.mcidas.AreaDirectoryList AreaDirectoryList}.
048 */
049public class ErrorCodeAreaUtils {
050
051    private static final Logger logger = LoggerFactory.getLogger(ErrorCodeAreaUtils.class);
052
053    public static final String GENERIC_EXCEPTION_MESSAGE = "Could not create VisAD data object.";
054
055    /**
056     * Disallow instances of {@code ErrorCodeAdapter}.
057     */
058    private ErrorCodeAreaUtils() { }
059
060    /**
061     * Create an {@code AreaAdapter} using the given {@code url}.
062     *
063     * @param url {@code URL} used to locate AREA. Cannot be {@code null}.
064     *
065     * @return Either the {@code AreaAdapter} for the given {@code url},
066     * or {@code null}.
067     *
068     * @throws AddeException if the {@code AreaAdapter} had problems.
069     */
070    public static AreaAdapter createAreaAdapter(final String url) throws AddeException {
071        AreaAdapter aa = null;
072        try {
073            aa = new AreaAdapter(url, false);
074        } catch (IOException e) {
075            int errorCode = searchStackTrace(e.getCause());
076            if (errorCode == 0) {
077                throw new AddeException("Could not connect to URL: " + url, e);
078            } else {
079                throw new AddeException(errorCode, GENERIC_EXCEPTION_MESSAGE, e);
080            }
081        } catch (VisADException e) {
082            int errorCode = searchStackTrace(e.getCause());
083            if (errorCode == 0) {
084                throw new AddeException(GENERIC_EXCEPTION_MESSAGE, e);
085            } else {
086                throw new AddeException(errorCode, GENERIC_EXCEPTION_MESSAGE, e);
087            }
088        }
089        return aa;
090    }
091
092    /**
093     * Create an {@code AreaDirectoryList} using the given {@code url}.
094     *
095     * @param url {@code URL} used to create AREA directory list. Cannot be {@code null}.
096     *
097     * @return Either the {@code AreaDirectoryList} for the given {@code url},
098     * or {@code null}.
099     *
100     * @throws AddeException if the {@code AreaDirectoryList} had problems.
101     */
102    public static AreaDirectoryList createAreaDirectoryList(final String url) throws AddeException {
103        AreaDirectoryList adl = null;
104        try {
105            adl = new AreaDirectoryList(url);
106        } catch (AreaFileException e) {
107//            logger.trace("exception='{}'", e);
108            int errorCode = searchStackTrace(e.getCause());
109            throw new AddeException(errorCode, GENERIC_EXCEPTION_MESSAGE, e);
110        }
111        return adl;
112    }
113
114    // yes. this approach is awful. but since i can't modify the visad code
115    // (which is what should be done!)...
116    private static int searchStackTrace(final Throwable cause) {
117        if ((cause == null) || (cause.getMessage() == null)) {
118            return -1;
119        }
120
121        String message = cause.getMessage().trim();
122        if ("DAY= must be used with archived datasets".equals(message)) {
123            return -1000;
124        } else if ("No images satisfy the selection criteria".equals(message)) {
125            return -5000;
126        } else if ("Accounting data was not valid".equals(message) || message.startsWith("Invalid project number:")) {
127            return -6000;
128        } else if ("Band keyword required for multi-banded image".equals(message) || "No BAND(s) specified".equals(message) || "Band required for multi-banded image".equals(message)) {
129            return -11011;
130        } else if (message.startsWith("Units requested are not available for this")) {
131            return -11007;
132        } else if ("The requested portion of the image does not exist".equals(message) || "The portion of the image requested does not exist".equals(message) || "Invalid Line SIZE specified".equals(message) || "Invalid Element SIZE specified".equals(message)) {
133            return -11010;
134        } else if ("Unable to initialize navigation for this image".equals(message)) {
135            return -11001;
136        } else if (message.endsWith("not present") || "Invalid BAND specified".equalsIgnoreCase(message) || "Invalid band number specified".equalsIgnoreCase(message) || "invalid band requested".equalsIgnoreCase(message)) {
137            return -11003;
138        } else if (message.startsWith("Band is not available in ") && message.endsWith(" units")) {
139            return -7000;
140        } else if (message.contains("requested Earth location is not contained in the image") || "Specified Lat/Lon not in image".equals(message)) {
141            return -11002;
142        } else if (message.startsWith("Image data server unable to resolve this dataset") || message.startsWith("Image directory server unable to resolve this dataset:")) {
143            return -118;
144        } else if (cause instanceof UnknownHostException) {
145            return -114;
146        } else {
147            Throwable nextCause = cause.getCause();
148            if (nextCause != null) {
149                return searchStackTrace(nextCause);
150            } else {
151                return 0;
152            }
153        }
154    }
155}