001/*
002 * **** BEGIN LICENSE BLOCK *****
003 *  Version: MPL 1.1/GPL 2.0/LGPL 2.1
004 *
005 *  The contents of this file are subject to the Mozilla Public License Version
006 *  1.1 (the "License"); you may not use this file except in compliance with
007 *  the License. You may obtain a copy of the License at
008 *  http://www.mozilla.org/MPL/
009 *
010 *  Software distributed under the License is distributed on an "AS IS" basis,
011 *  WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
012 *  for the specific language governing rights and limitations under the
013 *  License.
014 *
015 *  The Original Code is part of dcm4che, an implementation of DICOM(TM) in
016 *  Java(TM), hosted at https://github.com/gunterze/dcm4che.
017 *
018 *  The Initial Developer of the Original Code is
019 *  Agfa Healthcare.
020 *  Portions created by the Initial Developer are Copyright (C) 2014
021 *  the Initial Developer. All Rights Reserved.
022 *
023 *  Contributor(s):
024 *  See @authors listed below
025 *
026 *  Alternatively, the contents of this file may be used under the terms of
027 *  either the GNU General Public License Version 2 or later (the "GPL"), or
028 *  the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
029 *  in which case the provisions of the GPL or the LGPL are applicable instead
030 *  of those above. If you wish to allow use of your version of this file only
031 *  under the terms of either the GPL or the LGPL, and not to allow others to
032 *  use your version of this file under the terms of the MPL, indicate your
033 *  decision by deleting the provisions above and replace them with the notice
034 *  and other provisions required by the GPL or the LGPL. If you do not delete
035 *  the provisions above, a recipient may use your version of this file under
036 *  the terms of any one of the MPL, the GPL or the LGPL.
037 *
038 *  ***** END LICENSE BLOCK *****
039 */
040package org.dcm4che3.conf.core.util;
041
042import java.util.regex.Matcher;
043import java.util.regex.Pattern;
044
045/**
046 * Helper class that allows to safely set parameters for xpath patterns (by proper escaping) and to retrieve them from an escaped form
047 * ex: dicomConfigurationRoot/dicomDevicesRoot/*[dicomNetworkAE[@name='{aeName}']]/dicomDeviceName
048 */
049public class PathPattern {
050
051    String pattern;
052    private Pattern compiledPattern;
053
054    public PathPattern(String pattern) {
055        this.pattern = pattern;
056        this.compiledPattern = Pattern.compile(getParseRegex(pattern));
057    }
058
059    /**
060     *
061     * Converts
062     * <pre>
063     * /dicomConfigurationRoot/dicomDevicesRoot[@name='{deviceName}']
064     * </pre>
065     * to
066     * <pre>
067     * \Q/dicomConfigurationRoot/dicomDevicesRoot[@name='\E(?&lt;deviceName&gt;.*)\Q']\E
068     * </pre>
069     * @param pattern
070     * @return
071     */
072    private String getParseRegex(String pattern) {
073        String p = pattern;
074        String res = "";
075        try {
076            while (p.indexOf("{") > -1) {
077
078                // quote before
079                String piece = p.substring(0, p.indexOf("{"));
080                if (!piece.equals(""))
081                    res += Pattern.quote(piece);
082                p = p.substring(p.indexOf("{") + 1);
083
084                // add group
085                String varName = p.substring(0, p.indexOf("}"));
086                res += "(?<" + varName + ">.*)";
087
088                p = p.substring(p.indexOf("}") + 1);
089            }
090            // add rest if any
091            if (!p.equals("")) {
092                res += Pattern.quote(p);
093            }
094        } catch (IndexOutOfBoundsException e) {
095            throw new IllegalArgumentException("Path pattern " + pattern + " is invalid", e);
096        }
097        return res;
098    }
099
100    /**
101     * quick-start chaining
102     *
103     * @param paramName
104     * @param value
105     * @return
106     */
107    public PathCreator set(String paramName, String value) {
108        return createPath().set(paramName, value);
109    }
110
111    public String path() {
112        return pattern;
113    }
114
115
116    public PathCreator createPath() {
117        return new PathCreator();
118    }
119
120    public PathParser parse(String path) {
121
122        return new PathParser(path);
123    }
124
125    /**
126     * @return PathParser to retrieve params or null if the pattern does not match
127     */
128    public PathParser parseIfMatches(String path) {
129        Matcher matcher = compiledPattern.matcher(path);
130
131        if (matcher.matches())
132            return new PathParser(matcher);
133        else
134            return null;
135
136    }
137
138    public class PathParser {
139        private final Matcher matcher;
140
141        public PathParser(Matcher matcher) {
142            this.matcher = matcher;
143        }
144
145        public PathParser(String path) {
146            matcher = compiledPattern.matcher(path);
147            if (!matcher.matches()) throw new IllegalArgumentException("Path " + path + " is invalid");
148        }
149
150        public String getParam(String paramName) {
151            String str = matcher.group(paramName);
152            return str.replace("&apos;", "'");
153        }
154    }
155
156    public class PathCreator {
157
158        String res;
159
160        public PathCreator() {
161            res = pattern;
162        }
163
164        public PathCreator set(String paramName, String value) {
165            if (!res.contains(paramName))
166                throw new IllegalArgumentException("No parameter " + paramName + " in path " + res);
167            if (value == null)
168                throw new IllegalArgumentException("Attempted to set parameter " + paramName + " to NULL in path " + res);
169            res = res.replace("{" + paramName + "}", value.replace("'", "&apos;"));
170            return this;
171        }
172
173        public String path() {
174            return res;
175        }
176    }
177}