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.collections.*;
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 RestmRequestAttributes}
030 * </ul>
031 */
032public class RequestAttributes extends OMap {
033
034   private static final long serialVersionUID = 1L;
035
036   final RestRequest req;
037   final OMap defaultEntries;
038   final VarResolverSession vs;
039
040   RequestAttributes(RestRequest req, OMap 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 = req.getSession().getAttribute(k);
055      if (o == null)
056         o = defaultEntries.get(k);
057      return resolve(o);
058   }
059
060   @Override /* Map */
061   public Object put(String key, Object value) {
062      Object o = req.getAttribute(key);
063      req.setAttribute(key, value);
064      return o;
065   }
066
067   Object resolve(Object o) {
068      if (o instanceof CharSequence)
069         o = vs.resolve(o.toString());
070      return o;
071   }
072
073   @Override /* Map */
074   public Set<java.util.Map.Entry<String,Object>> entrySet() {
075      return new AbstractSet<java.util.Map.Entry<String,Object>>() {
076
077         @Override /* Set */
078         public Iterator<java.util.Map.Entry<String,Object>> iterator() {
079
080            return new Iterator<java.util.Map.Entry<String,Object>>() {
081               Set<String> keys = new LinkedHashSet<>();
082               {
083                  for (String s : iterable(req.getAttributeNames()))
084                     keys.add(s);
085                  for (String s : iterable(req.getSession().getAttributeNames()))
086                     keys.add(s);
087               }
088               Iterator<String> keyIterator = keys.iterator();
089               Iterator<Map.Entry<String,Object>> defaultsIterator = defaultEntries.entrySet().iterator();
090               Map.Entry<String,Object> peekNext;
091
092               @Override /* Iterator */
093               public boolean hasNext() {
094                  if (keyIterator.hasNext())
095                     return true;
096                  while (defaultsIterator.hasNext() && peekNext == null) {
097                     peekNext = defaultsIterator.next();
098                     if (keys.contains(peekNext.getKey()))
099                        peekNext = null;
100                  }
101                  return peekNext != null;
102               }
103
104               @Override /* Iterator */
105               public java.util.Map.Entry<String,Object> next() {
106                  if (keyIterator.hasNext()) {
107                     final String k = keyIterator.next();
108                     return new java.util.Map.Entry<String,Object>() {
109
110                        @Override /* Map.Entry */
111                        public String getKey() {
112                           return k;
113                        }
114
115                        @Override /* Map.Entry */
116                        public Object getValue() {
117                           return resolve(req.getAttribute(k));
118                        }
119
120                        @Override /* Map.Entry */
121                        public Object setValue(Object value) {
122                           Object o = req.getAttribute(k);
123                           req.setAttribute(k, value);
124                           return o;
125                        }
126                     };
127                  }
128                  while (defaultsIterator.hasNext() && peekNext == null) {
129                     peekNext = defaultsIterator.next();
130                     if (keys.contains(peekNext.getKey()))
131                        peekNext = null;
132                  }
133                  if (peekNext != null) {
134                     final java.util.Map.Entry<String,Object> o = peekNext;
135                     java.util.Map.Entry<String,Object> o2 = new java.util.Map.Entry<String,Object>() {
136
137                        @Override /* Map.Entry */
138                        public String getKey() {
139                           return o.getKey();
140                        }
141
142                        @Override /* Map.Entry */
143                        public Object getValue() {
144                           return resolve(o.getValue());
145                        }
146
147                        @Override /* Map.Entry */
148                        public Object setValue(Object value) {
149                           Object o3 = o.getValue();
150                           req.setAttribute(o.getKey(), value);
151                           return resolve(o3);
152                        }
153                     };
154                     peekNext = null;
155                     return o2;
156                  }
157                  return null;
158               }
159
160            };
161         }
162
163         @Override /* Set */
164         public int size() {
165            int i = defaultEntries.size();
166            for (String s : iterable(req.getAttributeNames()))
167               if (! defaultEntries.containsKey(s))
168                  i++;
169            return i;
170         }
171      };
172   }
173}