001/*
002 * #%L
003 * HAPI FHIR - Core Library
004 * %%
005 * Copyright (C) 2014 - 2024 Smile CDR, Inc.
006 * %%
007 * Licensed under the Apache License, Version 2.0 (the "License");
008 * you may not use this file except in compliance with the License.
009 * You may obtain a copy of the License at
010 *
011 *      http://www.apache.org/licenses/LICENSE-2.0
012 *
013 * Unless required by applicable law or agreed to in writing, software
014 * distributed under the License is distributed on an "AS IS" BASIS,
015 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
016 * See the License for the specific language governing permissions and
017 * limitations under the License.
018 * #L%
019 */
020package ca.uhn.fhir.model.primitive;
021
022import ca.uhn.fhir.model.api.BasePrimitive;
023import ca.uhn.fhir.model.api.annotation.DatatypeDef;
024import ca.uhn.fhir.model.api.annotation.SimpleSetter;
025import org.apache.commons.lang3.StringUtils;
026
027import java.net.URI;
028import java.net.URISyntaxException;
029
030@DatatypeDef(name = "uri")
031public class UriDt extends BasePrimitive<String> {
032
033        private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(UriDt.class);
034
035        /**
036         * Create a new String
037         */
038        public UriDt() {
039                // nothing
040        }
041
042        /**
043         * Create a new String
044         */
045        @SimpleSetter
046        public UriDt(@SimpleSetter.Parameter(name = "theUri") String theValue) {
047                setValueAsString(theValue);
048        }
049
050        @Override
051        protected String encode(String theValue) {
052                return theValue;
053        }
054
055        @Override
056        public boolean equals(Object obj) {
057                if (this == obj) return true;
058                if (obj == null) return false;
059                if (getClass() != obj.getClass()) return false;
060
061                UriDt other = (UriDt) obj;
062                if (getValue() == null && other.getValue() == null) {
063                        return true;
064                }
065                if (getValue() == null || other.getValue() == null) {
066                        return false;
067                }
068
069                String normalize = normalize(getValue());
070                String normalize2 = normalize(other.getValue());
071                return normalize.equals(normalize2);
072        }
073
074        /**
075         * Compares the given string to the string representation of this URI. In many cases it is preferable to use this
076         * instead of the standard {@link #equals(Object)} method, since that method returns <code>false</code> unless it is
077         * passed an instance of {@link UriDt}
078         */
079        public boolean equals(String theString) {
080                return StringUtils.equals(getValueAsString(), theString);
081        }
082
083        @Override
084        public int hashCode() {
085                final int prime = 31;
086                int result = 1;
087
088                String normalize = normalize(getValue());
089                result = prime * result + ((normalize == null) ? 0 : normalize.hashCode());
090
091                return result;
092        }
093
094        private String normalize(String theValue) {
095                if (theValue == null) {
096                        return null;
097                }
098                URI retVal;
099                try {
100                        retVal = new URI(theValue).normalize();
101                        String urlString = retVal.toString();
102                        if (urlString.endsWith("/") && urlString.length() > 1) {
103                                retVal = new URI(urlString.substring(0, urlString.length() - 1));
104                        }
105                } catch (URISyntaxException e) {
106                        ourLog.debug("Failed to normalize URL '{}', message was: {}", theValue, e.toString());
107                        return theValue;
108                }
109
110                return retVal.toASCIIString();
111        }
112
113        @Override
114        protected String parse(String theValue) {
115                return theValue;
116        }
117
118        /**
119         * Creates a new UriDt instance which uses the given OID as the content (and prepends "urn:oid:" to the OID string
120         * in the value of the newly created UriDt, per the FHIR specification).
121         *
122         * @param theOid
123         *           The OID to use (<code>null</code> is acceptable and will result in a UriDt instance with a
124         *           <code>null</code> value)
125         * @return A new UriDt instance
126         */
127        public static UriDt fromOid(String theOid) {
128                if (theOid == null) {
129                        return new UriDt();
130                }
131                return new UriDt("urn:oid:" + theOid);
132        }
133}