001/*
002 *  Licensed to the Apache Software Foundation (ASF) under one
003 *  or more contributor license agreements.  See the NOTICE file
004 *  distributed with this work for additional information
005 *  regarding copyright ownership.  The ASF licenses this file
006 *  to you under the Apache License, Version 2.0 (the
007 *  "License"); you may not use this file except in compliance
008 *  with the License.  You may obtain a copy of the License at
009 *
010 *    http://www.apache.org/licenses/LICENSE-2.0
011 *
012 *  Unless required by applicable law or agreed to in writing,
013 *  software distributed under the License is distributed on an
014 *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
015 *  KIND, either express or implied.  See the License for the
016 *  specific language governing permissions and limitations
017 *  under the License.
018 *
019 */
020package org.apache.mina.core.session;
021
022import java.util.HashMap;
023import java.util.HashSet;
024import java.util.Queue;
025import java.util.Set;
026import java.util.concurrent.ConcurrentHashMap;
027import java.util.concurrent.ConcurrentLinkedQueue;
028
029import org.apache.mina.core.write.WriteRequest;
030import org.apache.mina.core.write.WriteRequestQueue;
031
032/**
033 * The default {@link IoSessionDataStructureFactory} implementation
034 * that creates a new {@link HashMap}-based {@link IoSessionAttributeMap}
035 * instance and a new synchronized {@link ConcurrentLinkedQueue} instance per
036 * {@link IoSession}.
037 * 
038 * @author <a href="http://mina.apache.org">Apache MINA Project</a>
039 */
040public class DefaultIoSessionDataStructureFactory implements IoSessionDataStructureFactory {
041
042    public IoSessionAttributeMap getAttributeMap(IoSession session) throws Exception {
043        return new DefaultIoSessionAttributeMap();
044    }
045
046    public WriteRequestQueue getWriteRequestQueue(IoSession session) throws Exception {
047        return new DefaultWriteRequestQueue();
048    }
049
050    private static class DefaultIoSessionAttributeMap implements IoSessionAttributeMap {
051        private final ConcurrentHashMap<Object, Object> attributes = new ConcurrentHashMap<Object, Object>(4);
052
053        /**
054         * Default constructor
055         */
056        public DefaultIoSessionAttributeMap() {
057            super();
058        }
059
060        /**
061         * {@inheritDoc}
062         */
063        public Object getAttribute(IoSession session, Object key, Object defaultValue) {
064            if (key == null) {
065                throw new IllegalArgumentException("key");
066            }
067
068            if (defaultValue == null) {
069                return attributes.get(key);
070            }
071
072            Object object = attributes.putIfAbsent(key, defaultValue);
073
074            if (object == null) {
075                return defaultValue;
076            } else {
077                return object;
078            }
079        }
080
081        /**
082         * {@inheritDoc}
083         */
084        public Object setAttribute(IoSession session, Object key, Object value) {
085            if (key == null) {
086                throw new IllegalArgumentException("key");
087            }
088
089            if (value == null) {
090                return attributes.remove(key);
091            }
092
093            return attributes.put(key, value);
094        }
095
096        /**
097         * {@inheritDoc}
098         */
099        public Object setAttributeIfAbsent(IoSession session, Object key, Object value) {
100            if (key == null) {
101                throw new IllegalArgumentException("key");
102            }
103
104            if (value == null) {
105                return null;
106            }
107
108            return attributes.putIfAbsent(key, value);
109        }
110
111        /**
112         * {@inheritDoc}
113         */
114        public Object removeAttribute(IoSession session, Object key) {
115            if (key == null) {
116                throw new IllegalArgumentException("key");
117            }
118
119            return attributes.remove(key);
120        }
121
122        /**
123         * {@inheritDoc}
124         */
125        public boolean removeAttribute(IoSession session, Object key, Object value) {
126            if (key == null) {
127                throw new IllegalArgumentException("key");
128            }
129
130            if (value == null) {
131                return false;
132            }
133
134            try {
135                return attributes.remove(key, value);
136            } catch (NullPointerException e) {
137                return false;
138            }
139        }
140
141        /**
142         * {@inheritDoc}
143         */
144        public boolean replaceAttribute(IoSession session, Object key, Object oldValue, Object newValue) {
145            try {
146                return attributes.replace(key, oldValue, newValue);
147            } catch (NullPointerException e) {
148            }
149
150            return false;
151        }
152
153        /**
154         * {@inheritDoc}
155         */
156        public boolean containsAttribute(IoSession session, Object key) {
157            return attributes.containsKey(key);
158        }
159
160        /**
161         * {@inheritDoc}
162         */
163        public Set<Object> getAttributeKeys(IoSession session) {
164            synchronized (attributes) {
165                return new HashSet<Object>(attributes.keySet());
166            }
167        }
168
169        /**
170         * {@inheritDoc}
171         */
172        public void dispose(IoSession session) throws Exception {
173            // Do nothing
174        }
175    }
176
177    private static class DefaultWriteRequestQueue implements WriteRequestQueue {
178        /** A queue to store incoming write requests */
179        private final Queue<WriteRequest> q = new ConcurrentLinkedQueue<WriteRequest>();
180
181        /**
182         * Default constructor
183         */
184        public DefaultWriteRequestQueue() {
185        }
186
187        /**
188         * {@inheritDoc}
189         */
190        public void dispose(IoSession session) {
191            // Do nothing
192        }
193
194        /**
195         * {@inheritDoc}
196         */
197        public void clear(IoSession session) {
198            q.clear();
199        }
200
201        /**
202         * {@inheritDoc}
203         */
204        public boolean isEmpty(IoSession session) {
205            return q.isEmpty();
206        }
207
208        /**
209         * {@inheritDoc}
210         */
211        public void offer(IoSession session, WriteRequest writeRequest) {
212            q.offer(writeRequest);
213        }
214
215        /**
216         * {@inheritDoc}
217         */
218        public WriteRequest poll(IoSession session) {
219            WriteRequest answer = q.poll();
220
221            if (answer == AbstractIoSession.CLOSE_REQUEST) {
222                session.closeNow();
223                dispose(session);
224                answer = null;
225            }
226
227            return answer;
228        }
229
230        @Override
231        public String toString() {
232            return q.toString();
233        }
234
235        /**
236         * {@inheritDoc}
237         */
238        public int size() {
239            return q.size();
240        }
241    }
242}