001package org.conqat.engine.service.shared.client;
002
003import java.util.List;
004
005import org.conqat.engine.index.shared.CommitDescriptor;
006import org.conqat.engine.service.shared.ServiceUtils;
007import org.conqat.lib.commons.collections.ListMap;
008import org.conqat.lib.commons.collections.Pair;
009import org.conqat.lib.commons.string.StringUtils;
010import org.conqat.lib.commons.uniformpath.UniformPath;
011
012/** Methods to build Teamscale service URIs. */
013public class ServiceClientUris {
014
015        /** Prefix used to recognize projects. */
016        public static final String LEGACY_PROJECT_PREFIX = "p/";
017
018        /**
019         * Name of the boolean query parameter used to indicate recursive queries.
020         */
021        public static final String RECURSIVE_PARAMETER = "recursive";
022
023        /** Baselines parameter for findings service. */
024        public static final String BASELINE_PARAMETER = "baseline";
025
026        /** Include changed code findings parameter. */
027        public static final String INCLUDE_CHANGED_CODE_FINDINGS_PARAMETER = "include-changed-code-findings";
028
029        /** Principal metric index parameter for metric distribution service */
030        public static final String PRINCIPAL_METRIC_INDEX_PARAMETER = "principal-metric-index";
031
032        /** Metric index parameter for metric distribution service */
033        public static final String METRIC_INDEXES_PARAMETER = "metric-indexes";
034
035        /** Boundaries parameter for metric distribution service */
036        public static final String BOUNDARY_PARAMETER = "boundaries";
037
038        /** Name of the timestamp parameter. */
039        public static final String TIMESTAMP_PARAMETER_NAME = "t";
040
041        /** Name of the first timestamp parameter for delta queries. */
042        public static final String TIMESTAMP_ONE_PARAMETER_NAME = "t1";
043
044        /** Name of the second timestamp parameter for delta queries. */
045        public static final String TIMESTAMP_TWO_PARAMETER_NAME = "t2";
046
047        private ServiceClientUris() {
048                // Utils class should not be instantiated
049        }
050
051        /** Constructs a global service uri for services with api prefix. */
052        public static String getGlobal(String serviceName, ServerDetails serverDetails, Pair<?, ?>... options) {
053                return getGlobal(serviceName, serverDetails, toOptionsMap(options));
054        }
055
056        /** Constructs a global service uri for services with api prefix. */
057        public static String getGlobal(String serviceName, ServerDetails serverDetails, ListMap<String, String> options) {
058                return StringUtils.ensureEndsWith(serverDetails.getUrl(), "/") //
059                                + "api/" + serviceName + createOptionString(options);
060        }
061
062        /** Constructs a project service uri for services with api prefix. */
063        public static String getProject(String serviceName, ServerDetails serverDetails, String projectName,
064                        Pair<?, ?>... options) {
065                return getProject(serviceName, serverDetails, projectName, toOptionsMap(options));
066        }
067
068        /** Constructs a project service uri for services with api prefix. */
069        public static String getProject(String serviceName, ServerDetails serverDetails, String projectName,
070                        ListMap<String, String> options) {
071                return getProject(serviceName, serverDetails, projectName, StringUtils.EMPTY_STRING, options);
072        }
073
074        /** Constructs a project service uri for services with api prefix. */
075        public static String getProject(String serviceName, ServerDetails serverDetails, String projectName,
076                        UniformPath uniformPath, Pair<?, ?>... options) {
077                return getProject(serviceName, serverDetails, projectName, uniformPath.toString(), options);
078        }
079
080        /** Constructs a project service uri for services with api prefix. */
081        public static String getProject(String serviceName, ServerDetails serverDetails, String projectName,
082                        String uniformPath, Pair<?, ?>... options) {
083                return getProject(serviceName, serverDetails, projectName, uniformPath, toOptionsMap(options));
084        }
085
086        /** Constructs a project service uri for services with api prefix. */
087        public static String getProject(String serviceName, ServerDetails serverDetails, String projectName,
088                        UniformPath uniformPath, ListMap<String, String> options) {
089                return getProject(serviceName, serverDetails, projectName, uniformPath.toString(), options);
090        }
091
092        /** Constructs a project service uri for services with api prefix. */
093        public static String getProject(String serviceName, ServerDetails serverDetails, String projectName,
094                        String uniformPath, ListMap<String, String> options) {
095                return StringUtils.ensureEndsWith(serverDetails.getUrl(), "/") //
096                                + "api/projects/" + projectName + "/" //
097                                + serviceName + "/" //
098                                + ServiceUtils.encodeUniformPath(uniformPath) //
099                                + createOptionString(options);
100        }
101
102        /** Class for building URI's for legacy services. */
103        public static class Legacy {
104
105                /** Constructs a global service uri for services of the legacy framework. */
106                public static String getGlobal(String serviceName, ServerDetails serverDetails, Pair<?, ?>... options) {
107                        return getGlobal(serviceName, serverDetails, toOptionsMap(options));
108                }
109
110                /** Constructs a global service uri for services of the legacy framework. */
111                public static String getGlobal(String serviceName, ServerDetails serverDetails,
112                                ListMap<String, String> options) {
113                        return getServiceUrl(serverDetails, null, serviceName) + createOptionString(options);
114                }
115
116                /** Constructs a project service uri for services of the legacy framework. */
117                public static String getProject(String serviceName, ServerDetails serverDetails, String projectName,
118                                Pair<?, ?>... options) {
119                        return getProject(serviceName, serverDetails, projectName, toOptionsMap(options));
120                }
121
122                /** Constructs a project service uri for services of the legacy framework. */
123                public static String getProject(String serviceName, ServerDetails serverDetails, String projectName,
124                                String uniformPath, Pair<?, ?>... options) {
125                        return getProject(serviceName, serverDetails, projectName, uniformPath, toOptionsMap(options));
126                }
127
128                /** Constructs a project service uri for services of the legacy framework. */
129                public static String getProject(String serviceName, ServerDetails serverDetails, String projectName,
130                                String uniformPath, ListMap<String, String> options) {
131                        return getServiceUrl(serverDetails, projectName, serviceName) //
132                                        + ServiceUtils.encodeUniformPath(uniformPath) //
133                                        + createOptionString(options);
134                }
135
136                /** Constructs a project service uri for services of the legacy framework. */
137                public static String getProject(String serviceName, ServerDetails serverDetails, String projectName,
138                                UniformPath uniformPath, Pair<?, ?> options) {
139                        return getProject(serviceName, serverDetails, projectName, uniformPath, toOptionsMap(options));
140                }
141
142                /** Constructs a project service uri for services of the legacy framework. */
143                public static String getProject(String serviceName, ServerDetails serverDetails, String projectName,
144                                UniformPath uniformPath, ListMap<String, String> options) {
145                        return getProject(serviceName, serverDetails, projectName, uniformPath.toString(), options);
146                }
147
148                /** Constructs a project service uri for services of the legacy framework. */
149                public static String getProject(String serviceName, ServerDetails serverDetails, String projectName,
150                                ListMap<String, String> options) {
151                        return getServiceUrl(serverDetails, projectName, serviceName) //
152                                        + createOptionString(options);
153                }
154
155                /** Constructs the URL of a service. */
156                private static String getServiceUrl(ServerDetails serverDetails, String projectName, String serviceName) {
157                        String url = serverDetails.getUrl();
158                        url = StringUtils.ensureEndsWith(url, "/");
159
160                        if (projectName != null) {
161                                url += StringUtils.ensureEndsWith(LEGACY_PROJECT_PREFIX + projectName, "/");
162                        }
163                        url = StringUtils.ensureEndsWith(url, "/");
164
165                        url += serviceName;
166                        url = StringUtils.ensureEndsWith(url, "/");
167
168                        return url;
169                }
170        }
171
172        /**
173         * @return the given options as a {@link ListMap} or {@code null}, if no options
174         *         are given.
175         */
176        private static ListMap<String, String> toOptionsMap(Pair<?, ?>... options) {
177                if (options.length == 0) {
178                        return null;
179                }
180                ListMap<String, String> optionsMap = new ListMap<>();
181                for (Pair<?, ?> option : options) {
182                        if (option != null) {
183                                optionsMap.add(option.getFirst().toString(), option.getSecond().toString());
184                        }
185                }
186                return optionsMap;
187        }
188
189        /**
190         * Creates an encoded URL options string starting with <code>?</code> from the
191         * given options. The given parameters are interpreted as parameter names and
192         * values, where each odd numbered parameter is a parameter name and each even
193         * one is the corresponding value.
194         */
195        public static String createOptionString(String... parametersAndValues) {
196                return createOptionString(ListMap.of(parametersAndValues));
197        }
198
199        /**
200         * Creates an encoded URL options string starting with <code>?</code> from the
201         * given options.
202         */
203        private static String createOptionString(ListMap<String, String> options) {
204                StringBuilder sb = new StringBuilder();
205                if (options != null) {
206                        String separator = "?";
207                        for (String option : options.getKeys()) {
208                                List<String> values = options.getCollection(option);
209                                for (String value : values) {
210                                        value = ServiceUtils.encodeQueryParameter(value);
211                                        sb.append(separator).append(option).append('=').append(value);
212                                        separator = "&";
213                                }
214                        }
215                }
216                return sb.toString();
217        }
218
219        /**
220         * Creates a timestamp parameter pair. When the timestamp is null the method
221         * returns <code>null</code>.
222         */
223        public static Pair<String, String> createCommitDescriptorOption(CommitDescriptor commitDescriptor) {
224                if (commitDescriptor == null) {
225                        return null;
226                }
227                return Pair.createPair(TIMESTAMP_PARAMETER_NAME, commitDescriptor.toServiceCallFormat());
228        }
229
230}