001// ***************************************************************************************************************************
002// * Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements.  See the NOTICE file *
003// * distributed with this work for additional information regarding copyright ownership.  The ASF licenses this file        *
004// * to you under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance            *
005// * with the License.  You may obtain a copy of the License at                                                              *
006// *                                                                                                                         *
007// *  http://www.apache.org/licenses/LICENSE-2.0                                                                             *
008// *                                                                                                                         *
009// * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an  *
010// * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the License for the        *
011// * specific language governing permissions and limitations under the License.                                              *
012// ***************************************************************************************************************************
013package org.apache.juneau.rest;
014
015import static org.apache.juneau.internal.CollectionUtils.*;
016
017import java.util.*;
018
019import org.apache.juneau.*;
020import org.apache.juneau.svl.*;
021
022/**
023 * Represents the attributes in an HTTP request.
024 *
025 * <p>
026 * Wraps the request attributes in a {@link Map} interface and provides several convenience methods.
027 *
028 * <ul class='seealso'>
029 *    <li class='link'>{@doc juneau-rest-server.RestMethod.RequestAttributes}
030 * </ul>
031 */
032public class RequestAttributes extends ObjectMap {
033
034   private static final long serialVersionUID = 1L;
035
036   final RestRequest req;
037   final ObjectMap defaultEntries;
038   final VarResolverSession vs;
039
040   RequestAttributes(RestRequest req, ObjectMap defaultEntries) {
041      super();
042      this.req = req;
043      this.defaultEntries = defaultEntries;
044      this.vs = req.getVarResolverSession();
045   }
046
047   @Override /* Map */
048   public Object get(Object key) {
049      if (key == null)
050         return null;
051      String k = key.toString();
052      Object o = req.getAttribute(k);
053      if (o == null)
054         o = defaultEntries.get(k);
055      return resolve(o);
056   }
057
058   @Override /* Map */
059   public Object put(String key, Object value) {
060      Object o = req.getAttribute(key);
061      req.setAttribute(key, value);
062      return o;
063   }
064
065   Object resolve(Object o) {
066      if (o instanceof CharSequence)
067         o = vs.resolve(o.toString());
068      return o;
069   }
070
071   @Override /* Map */
072   public Set<java.util.Map.Entry<String,Object>> entrySet() {
073      return new AbstractSet<java.util.Map.Entry<String,Object>>() {
074
075         @Override /* Set */
076         public Iterator<java.util.Map.Entry<String,Object>> iterator() {
077
078            return new Iterator<java.util.Map.Entry<String,Object>>() {
079               Set<String> keys = new LinkedHashSet<>();
080               {
081                  for (String s : iterable(req.getAttributeNames()))
082                     keys.add(s);
083               }
084               Iterator<String> keyIterator = keys.iterator();
085               Iterator<Map.Entry<String,Object>> defaultsIterator = defaultEntries.entrySet().iterator();
086               Map.Entry<String,Object> peekNext;
087
088               @Override /* Iterator */
089               public boolean hasNext() {
090                  if (keyIterator.hasNext())
091                     return true;
092                  while (defaultsIterator.hasNext() && peekNext == null) {
093                     peekNext = defaultsIterator.next();
094                     if (keys.contains(peekNext.getKey()))
095                        peekNext = null;
096                  }
097                  return peekNext != null;
098               }
099
100               @Override /* Iterator */
101               public java.util.Map.Entry<String,Object> next() {
102                  if (keyIterator.hasNext()) {
103                     final String k = keyIterator.next();
104                     return new java.util.Map.Entry<String,Object>() {
105
106                        @Override /* Map.Entry */
107                        public String getKey() {
108                           return k;
109                        }
110
111                        @Override /* Map.Entry */
112                        public Object getValue() {
113                           return resolve(req.getAttribute(k));
114                        }
115
116                        @Override /* Map.Entry */
117                        public Object setValue(Object value) {
118                           Object o = req.getAttribute(k);
119                           req.setAttribute(k, value);
120                           return o;
121                        }
122                     };
123                  }
124                  while (defaultsIterator.hasNext() && peekNext == null) {
125                     peekNext = defaultsIterator.next();
126                     if (keys.contains(peekNext.getKey()))
127                        peekNext = null;
128                  }
129                  if (peekNext != null) {
130                     final java.util.Map.Entry<String,Object> o = peekNext;
131                     java.util.Map.Entry<String,Object> o2 = new java.util.Map.Entry<String,Object>() {
132
133                        @Override /* Map.Entry */
134                        public String getKey() {
135                           return o.getKey();
136                        }
137
138                        @Override /* Map.Entry */
139                        public Object getValue() {
140                           return resolve(o.getValue());
141                        }
142
143                        @Override /* Map.Entry */
144                        public Object setValue(Object value) {
145                           Object o3 = o.getValue();
146                           req.setAttribute(o.getKey(), value);
147                           return resolve(o3);
148                        }
149                     };
150                     peekNext = null;
151                     return o2;
152                  }
153                  return null;
154               }
155
156            };
157         }
158
159         @Override /* Set */
160         public int size() {
161            int i = defaultEntries.size();
162            for (String s : iterable(req.getAttributeNames()))
163               if (! defaultEntries.containsKey(s))
164                  i++;
165            return i;
166         }
167      };
168   }
169}