001package systems.dmx.core.util;
002
003import javax.servlet.http.Cookie;
004import javax.servlet.http.HttpServletRequest;
005import javax.ws.rs.core.Response;
006
007import java.io.File;
008import java.io.FileInputStream;
009import java.io.InputStream;
010import java.io.UnsupportedEncodingException;
011
012import java.math.BigInteger;
013
014import java.net.FileNameMap;
015import java.net.InetAddress;
016import java.net.Inet4Address;
017import java.net.Inet6Address;
018import java.net.URL;
019import java.net.URLConnection;
020import java.net.URLDecoder;
021import java.net.URLEncoder;
022
023import java.security.MessageDigest;
024import java.security.NoSuchAlgorithmException;
025
026import java.util.Map;
027import java.util.Scanner;
028
029
030
031/**
032 * Generic Java utilities.
033 */
034public class JavaUtils {
035
036
037
038    // === Text ===
039
040    public static String stripHTML(String html) {
041        return html.replaceAll("<.*?>", "");    // *? is the reluctant version of the * quantifier (which is greedy)
042    }
043
044    public static String times(String str, int times) {
045        StringBuilder sb = new StringBuilder(times * str.length());
046        for (int i = 0; i < times; i++) {
047            sb.append(str);
048        }
049        return sb.toString();
050    }
051
052
053
054    // === Files ===
055
056    private static FileNameMap fileTypeMap = URLConnection.getFileNameMap();
057
058    public static String getFileType(String fileName) {
059        String extension = getExtension(fileName);
060        if (!extension.equals("avi")) {
061            // Note: for .avi Java's file type map returns strange media type "application/x-troff-msvideo".
062            // See lib/content-types.properties under java home.
063            String fileType = fileTypeMap.getContentTypeFor(fileName);
064            if (fileType != null) {
065                return fileType;
066            }
067        }
068        // fallback
069        if (extension.equals("json")) {
070            return "application/json";
071        } else if (extension.equals("mp3")) {
072            return "audio/mpeg";
073        } else if (extension.equals("mp4")) {
074            return "video/mp4";
075        } else if (extension.equals("avi")) {
076            return "video/avi";
077        } else if (extension.equals("wmv")) {
078            return "video/x-ms-wmv";
079        } else if (extension.equals("flv")) {
080            return "video/x-flv";
081        } else if (extension.equals("svg")) {
082            return "image/svg+xml";
083        }
084        // TODO: use a system property instead a hardcoded list
085        //
086        return null;
087    }
088
089    public static String getFilename(String path) {
090        return path.substring(path.lastIndexOf('/') + 1);
091    }
092
093    public static String getBasename(String fileName) {
094        int i = fileName.lastIndexOf(".");
095        if (i == -1) {
096            return fileName;
097        }
098        return fileName.substring(0, i);
099    }
100
101    public static String getExtension(String fileName) {
102        return fileName.substring(fileName.lastIndexOf(".") + 1).toLowerCase();
103    }
104
105    public static String stripDriveLetter(String path) {
106        return path.replaceFirst("^[A-Z]:", "");
107    }
108
109    // ---
110
111    public static File findUnusedFile(File file) {
112        String parent = file.getParent();
113        String fileName = file.getName();
114        String basename = getBasename(fileName);
115        String extension = getExtension(fileName);
116        int nr = 1;
117        while (file.exists()) {
118            nr++;
119            file = new File(parent, basename + "-" + nr + "." + extension);
120        }
121        return file;
122    }
123
124    // ---
125
126    public static String readTextFile(File file) {
127        try {
128            return readText(new FileInputStream(file));
129        } catch (Exception e) {
130            throw new RuntimeException("Reading text file \"" + file + "\" failed", e);
131        }
132    }
133
134    public static String readText(InputStream in) {
135        StringBuilder text = new StringBuilder();
136        Scanner scanner = new Scanner(in);
137        while (scanner.hasNextLine()) {
138            text.append(scanner.nextLine() + "\n");
139        }
140        return text.toString();
141    }
142
143    // ---
144
145    public static File createTempDirectory(String prefix) {
146        try {
147            File f = File.createTempFile(prefix, ".dir");
148            String n = f.getAbsolutePath();
149            f.delete();
150            f = new File(n);
151            f.mkdir();
152            return f;
153        } catch (Exception e) {
154            throw new RuntimeException("Creating temporary directory failed", e);
155        }
156    }
157
158
159
160    // === URLs ===
161
162    public static String readTextURL(URL url) {
163        try {
164            return readText(url.openStream());
165        } catch (Exception e) {
166            throw new RuntimeException("Reading from URL \"" + url + "\" failed", e);
167        }
168    }
169
170    // ---
171
172    public static String encodeURIComponent(String uriComp) {
173        try {
174            return URLEncoder.encode(uriComp, "UTF-8").replaceAll("\\+", "%20");
175        } catch (UnsupportedEncodingException e) {
176            throw new RuntimeException("Encoding URI component \"" + uriComp + "\" failed", e);
177        }
178    }
179
180    public static String decodeURIComponent(String uriComp) {
181        try {
182            return URLDecoder.decode(uriComp, "UTF-8");
183        } catch (UnsupportedEncodingException e) {
184            throw new RuntimeException("Decoding URI component \"" + uriComp + "\" failed", e);
185        }
186    }
187
188
189
190    // === Networking ===
191
192    /**
193     * @param   inetAddress     IPv4 or IPv6 address or a machine name, e.g. "172.68.8.12"
194     * @param   range           IPv4 or IPv6 address range in CIDR notation, e.g. "172.68.8.0/24"
195     */
196    public static boolean isInRange(String inetAddress, String range) {
197        try {
198            String[] r = range.split("/");
199            BigInteger networkAddr = inetAddress(r[0]);
200            int maskNumber = Integer.parseInt(r[1]);
201            InetAddress addr = InetAddress.getByName(inetAddress);
202            BigInteger networkMask = networkMask(addr, maskNumber);
203            //
204            return inetAddress(addr).xor(networkAddr).and(networkMask).equals(BigInteger.ZERO);
205        } catch (Exception e) {
206            throw new RuntimeException("Checking IP range failed (inetAddress=\"" + inetAddress +
207                "\", range=\"" + range + "\"", e);
208        }
209    }
210
211    // ---
212
213    public static BigInteger inetAddress(String inetAddress) {
214        try {
215            return inetAddress(InetAddress.getByName(inetAddress));
216        } catch (Exception e) {
217            throw new RuntimeException("Parsing inet address \"" + inetAddress + "\" failed", e);
218        }
219    }
220
221    public static BigInteger inetAddress(InetAddress inetAddress) {
222        return new BigInteger(1, inetAddress.getAddress());     // signum=1 (positive)
223    }
224
225    // ---
226
227    public static BigInteger networkMask(InetAddress addr, int maskNumber) {
228        if (addr instanceof Inet4Address) {
229            return networkMask(maskNumber, 32);
230        } else if (addr instanceof Inet6Address) {
231            return networkMask(maskNumber, 128);
232        } else {
233            throw new RuntimeException("Unexpected InetAddress object: " + addr.getClass().getName());
234        }
235    }
236
237    public static BigInteger networkMask(int maskNumber, int size) {
238        String networkMask = times("1", maskNumber) + times("0", size - maskNumber);
239        return new BigInteger(networkMask, 2);      // radix=2 (binary)
240    }
241
242    // ---
243
244    public static String cookieValue(HttpServletRequest request, String cookieName) {
245        for (Cookie cookie : request.getCookies()) {
246            if (cookie.getName().equals(cookieName)) {
247                return cookie.getValue();
248            }
249        }
250        return null;
251    }
252
253    // ---
254
255    public static String requestInfo(HttpServletRequest request) {
256        String queryString = request.getQueryString();
257        return request.getMethod() + " " + request.getRequestURI() + (queryString != null ? "?" + queryString : "");
258    }
259
260    public static String responseInfo(Response.StatusType status) {
261        return status.getStatusCode() + " (" + status.getReasonPhrase() + ")";
262    }
263
264    // ---
265
266    public static String requestDump(HttpServletRequest request) {
267        StringBuilder dump = new StringBuilder(request + ", session=" + request.getSession(false) + ", cookies=");
268        for (Cookie cookie : request.getCookies()) {
269            dump.append("\n  " + cookie.getName() + "=" + cookie.getValue());
270        }
271        return dump.toString();
272    }
273
274
275
276    // === Encoding ===
277
278    /* static {
279        for (Provider p : Security.getProviders()) {
280            System.out.println("### Security Provider " + p);
281            for (Provider.Service s : p.getServices()) {
282                System.out.println("        " + s);
283            }
284        }
285    } */
286
287    public static String encodeSHA256(String data) {
288        try {
289            MessageDigest sha256 = MessageDigest.getInstance("SHA-256");
290            return new String(encodeHex(sha256.digest(data.getBytes())));
291        } catch (NoSuchAlgorithmException e) {
292            throw new RuntimeException("SHA256 encoding failed", e);
293        }
294    }
295
296    private static char[] encodeHex(byte[] data) {
297        final String DIGITS = "0123456789abcdef";
298        int l = data.length;
299        char[] out = new char[l << 1];
300        // two characters form the hex value
301        for (int i = 0, j = 0; i < l; i++) {
302            out[j++] = DIGITS.charAt((0xF0 & data[i]) >>> 4);
303            out[j++] = DIGITS.charAt(0x0F & data[i]);
304        }
305        return out;
306    }
307}