1/*
2 * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation.  Oracle designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Oracle in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 */
25
26package com.sun.xml.internal.ws.client;
27
28import com.sun.xml.internal.ws.api.message.Packet;
29import com.sun.xml.internal.ws.api.message.AttachmentSet;
30import com.sun.xml.internal.ws.api.message.Attachment;
31
32import javax.xml.ws.handler.MessageContext;
33import javax.activation.DataHandler;
34import java.util.AbstractMap;
35import java.util.Collections;
36import java.util.HashMap;
37import java.util.Map;
38import java.util.Set;
39
40/**
41 * Implements "response context" on top of {@link Packet}.
42 *
43 * <p>
44 * This class creates a read-only {@link Map} view that
45 * gets exposed to client applications after an invocation
46 * is complete.
47 *
48 * <p>
49 * The design goal of this class is to make it efficient
50 * to create a new {@link ResponseContext}, at the expense
51 * of making some {@link Map} operations slower. This is
52 * justified because the response context is mostly just
53 * used to query a few known values, and operations like
54 * enumeration isn't likely.
55 *
56 * <p>
57 * Some of the {@link Map} methods requre this class to
58 * build the complete {@link Set} of properties, but we
59 * try to avoid that as much as possible.
60 *
61 *
62 * <pre>
63 * TODO: are we exposing all strongly-typed fields, or
64 * do they have appliation/handler scope notion?
65 * </pre>
66 *
67 * @author Kohsuke Kawaguchi
68 */
69@SuppressWarnings({"SuspiciousMethodCalls"})    // IDE doesn't like me calling Map methods with key typed as Object
70public class ResponseContext extends AbstractMap<String,Object> {
71    private final Packet packet;
72
73    /**
74     * Lazily computed.
75     */
76    private Set<Map.Entry<String,Object>> entrySet;
77
78    /**
79     * @param packet
80     *      The {@link Packet} to wrap.
81     */
82    public ResponseContext(Packet packet) {
83        this.packet = packet;
84    }
85
86    public boolean containsKey(Object key) {
87        if(packet.supports(key))
88            return packet.containsKey(key);    // strongly typed
89
90        if(packet.invocationProperties.containsKey(key))
91            // if handler-scope, hide it
92            return !packet.getHandlerScopePropertyNames(true).contains(key);
93
94        return false;
95    }
96
97    public Object get(Object key) {
98        if(packet.supports(key))
99            return packet.get(key);    // strongly typed
100
101        if(packet.getHandlerScopePropertyNames(true).contains(key))
102            return null;            // no such application-scope property
103
104        Object value =  packet.invocationProperties.get(key);
105
106        //add the attachments from the Message to the corresponding attachment property
107        if(key.equals(MessageContext.INBOUND_MESSAGE_ATTACHMENTS)){
108            Map<String, DataHandler> atts = (Map<String, DataHandler>) value;
109            if(atts == null)
110                atts = new HashMap<String, DataHandler>();
111            AttachmentSet attSet = packet.getMessage().getAttachments();
112            for(Attachment att : attSet){
113                atts.put(att.getContentId(), att.asDataHandler());
114            }
115            return atts;
116        }
117        return value;
118    }
119
120    public Object put(String key, Object value) {
121        // response context is read-only
122        throw new UnsupportedOperationException();
123    }
124
125    public Object remove(Object key) {
126        // response context is read-only
127        throw new UnsupportedOperationException();
128    }
129
130    public void putAll(Map<? extends String, ? extends Object> t) {
131        // response context is read-only
132        throw new UnsupportedOperationException();
133    }
134
135    public void clear() {
136        // response context is read-only
137        throw new UnsupportedOperationException();
138    }
139
140    public Set<Entry<String, Object>> entrySet() {
141        if(entrySet==null) {
142            // this is where the worst case happens. we have to clone the whole properties
143            // to get this view.
144
145            // use TreeSet so that toString() sort them nicely. It's easier for apps.
146            Map<String,Object> r = new HashMap<String,Object>();
147
148            // export application-scope properties
149            r.putAll(packet.invocationProperties);
150
151            // hide handler-scope properties
152            r.keySet().removeAll(packet.getHandlerScopePropertyNames(true));
153
154            // and all strongly typed ones
155            r.putAll(packet.createMapView());
156
157            entrySet = Collections.unmodifiableSet(r.entrySet());
158        }
159
160        return entrySet;
161    }
162
163}
164