001/*
002 * This file is part of the JDrupes non-blocking HTTP Codec
003 * Copyright (C) 2017 Michael N. Lipp
004 *
005 * This program is free software; you can redistribute it and/or modify it 
006 * under the terms of the GNU Lesser General Public License as published
007 * by the Free Software Foundation; either version 3 of the License, or 
008 * (at your option) any later version.
009 *
010 * This program is distributed in the hope that it will be useful, but 
011 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
012 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public 
013 * License for more details.
014 *
015 * You should have received a copy of the GNU Lesser General Public License along 
016 * with this program; if not, see <http://www.gnu.org/licenses/>.
017 */
018
019package org.jdrupes.httpcodec.types;
020
021import java.text.ParseException;
022import java.util.Collections;
023import java.util.Map;
024
025public abstract class MediaBase 
026        extends ParameterizedValue<MediaBase.MediaTypePair> {
027
028        /**
029         * Create a new object with the given type and no parameters.
030         * 
031         * @param type the type
032         */
033        protected MediaBase(MediaTypePair type) {
034                super(type, Collections.emptyMap());
035        }
036
037        /**
038         * Create a new object with the given type and parameters.
039         * 
040         * @param type the type
041         * @param parameters the parameters
042         */
043        protected MediaBase(MediaTypePair type, Map<String, String> parameters) {
044                super(type, parameters);
045        }
046
047        /**
048         * Returns the top-level type.
049         * 
050         * @return the type
051         */
052        public String topLevelType() {
053                return value().topLevelType;
054        }
055        
056        /**
057         * Returns the subtype
058         * 
059         * @return the subtype
060         */
061        public String subtype() {
062                return value().subtype;
063        }
064
065        /**
066         * Represents the tuple media top-level type and subtype, 
067         * including a media range (type or subtype
068         * equals "`*`").
069         */
070        public static class MediaTypePair {
071                
072                public static final MediaTypePair ALL_MEDIA 
073                        = new MediaTypePair("*", "*");
074                
075                private String topLevelType;
076                private String subtype;
077                
078                /**
079                 * Create a new object with the given type and subtype.
080                 * 
081                 * @param type the type
082                 * @param subtype the subtype
083                 */
084                public MediaTypePair(String type, String subtype) {
085                        super();
086                        this.topLevelType = type.toLowerCase();
087                        this.subtype = subtype.toLowerCase();
088                }
089                
090                /**
091                 * Create a main type from its textual representation. 
092                 * 
093                 * @param text the textual representation
094                 * @return the result
095                 * @throws ParseException if the text is ill-formed
096                 */
097                public static MediaTypePair fromString(String text) 
098                                throws ParseException {
099                        int sepPos = text.indexOf('/');
100                        if (sepPos <= 0 || sepPos > text.length() - 2) {
101                                throw new ParseException(
102                                                "Format not \"type/subtype\": " + text, 0);
103                        }
104                        return new MediaTypePair(text.substring(0, sepPos),
105                                        text.substring(sepPos + 1));
106                        
107                }
108                
109                /**
110                 * Returns the top-level type.
111                 * 
112                 * @return the type
113                 */
114                public String topLevelType() {
115                        return topLevelType;
116                }
117                
118                /**
119                 * Returns the subtype
120                 * 
121                 * @return the subtype
122                 */
123                public String subtype() {
124                        return subtype;
125                }
126
127                /* (non-Javadoc)
128                 * @see java.lang.Object#toString()
129                 */
130                @Override
131                public String toString() {
132                        return topLevelType + "/" + subtype;
133                }
134
135                /* (non-Javadoc)
136                 * @see java.lang.Object#hashCode()
137                 */
138                @Override
139                public int hashCode() {
140                        final int prime = 31;
141                        int result = 1;
142                        result = prime * result
143                                + ((subtype == null) ? 0 : subtype.hashCode());
144                        result = prime * result + ((topLevelType == null) ? 0 : topLevelType.hashCode());
145                        return result;
146                }
147
148                /* (non-Javadoc)
149                 * @see java.lang.Object#equals(java.lang.Object)
150                 */
151                @Override
152                public boolean equals(Object obj) {
153                        if (this == obj) {
154                                return true;
155                        }
156                        if (obj == null) {
157                                return false;
158                        }
159                        if (getClass() != obj.getClass()) {
160                                return false;
161                        }
162                        MediaBase.MediaTypePair other = (MediaBase.MediaTypePair) obj;
163                        if (subtype == null) {
164                                if (other.subtype != null) {
165                                        return false;
166                                }
167                        } else if (!subtype.equals(other.subtype)) {
168                                return false;
169                        }
170                        if (topLevelType == null) {
171                                if (other.topLevelType != null) {
172                                        return false;
173                                }
174                        } else if (!topLevelType.equals(other.topLevelType)) {
175                                return false;
176                        }
177                        return true;
178                }
179        }
180        
181        public static class MediaTypePairConverter
182                implements Converter<MediaTypePair> {
183
184                @Override
185                public String asFieldValue(MediaTypePair value) {
186                        return value.toString();
187                }
188
189                @Override
190                public MediaTypePair fromFieldValue(String text)
191                                throws ParseException {
192                        return MediaTypePair.fromString(text);
193                }
194        }
195
196}