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            super();
186        }
187
188        /**
189         * {@inheritDoc}
190         */
191        public void dispose(IoSession session) {
192            // Do nothing
193        }
194
195        /**
196         * {@inheritDoc}
197         */
198        public void clear(IoSession session) {
199            q.clear();
200        }
201
202        /**
203         * {@inheritDoc}
204         */
205        public synchronized boolean isEmpty(IoSession session) {
206            return q.isEmpty();
207        }
208
209        /**
210         * {@inheritDoc}
211         */
212        public synchronized void offer(IoSession session, WriteRequest writeRequest) {
213            q.offer(writeRequest);
214        }
215
216        /**
217         * {@inheritDoc}
218         */
219        public synchronized WriteRequest poll(IoSession session) {
220            return q.poll();
221        }
222
223        @Override
224        public String toString() {
225            return q.toString();
226        }
227
228        /**
229         * {@inheritDoc}
230         */
231        public int size() {
232            return q.size();
233        }
234    }
235}