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.assembler;
27
28import com.sun.istack.internal.NotNull;
29import com.sun.istack.internal.logging.Logger;
30import com.sun.xml.internal.ws.api.BindingID;
31import com.sun.xml.internal.ws.api.pipe.ClientTubeAssemblerContext;
32import com.sun.xml.internal.ws.api.pipe.ServerTubeAssemblerContext;
33import com.sun.xml.internal.ws.api.pipe.Tube;
34import com.sun.xml.internal.ws.api.pipe.TubelineAssembler;
35import com.sun.xml.internal.ws.assembler.dev.TubelineAssemblyDecorator;
36import com.sun.xml.internal.ws.dump.LoggingDumpTube;
37import com.sun.xml.internal.ws.resources.TubelineassemblyMessages;
38import com.sun.xml.internal.ws.util.ServiceFinder;
39
40import java.util.Collection;
41import java.util.logging.Level;
42
43/**
44* TODO: Write some description here ...
45*
46* @author Miroslav Kos (miroslav.kos at oracle.com)
47*/
48public class MetroTubelineAssembler implements TubelineAssembler {
49
50    private static final String COMMON_MESSAGE_DUMP_SYSTEM_PROPERTY_BASE = "com.sun.metro.soap.dump";
51    public static final MetroConfigNameImpl JAXWS_TUBES_CONFIG_NAMES = new MetroConfigNameImpl("jaxws-tubes-default.xml", "jaxws-tubes.xml");
52
53    private static enum Side {
54
55        Client("client"),
56        Endpoint("endpoint");
57        private final String name;
58
59        private Side(String name) {
60            this.name = name;
61        }
62
63        @Override
64        public String toString() {
65            return name;
66        }
67    }
68
69    private static class MessageDumpingInfo {
70
71        final boolean dumpBefore;
72        final boolean dumpAfter;
73        final Level logLevel;
74
75        MessageDumpingInfo(boolean dumpBefore, boolean dumpAfter, Level logLevel) {
76            this.dumpBefore = dumpBefore;
77            this.dumpAfter = dumpAfter;
78            this.logLevel = logLevel;
79        }
80    }
81
82    private static final Logger LOGGER = Logger.getLogger(MetroTubelineAssembler.class);
83    private final BindingID bindingId;
84    private final TubelineAssemblyController tubelineAssemblyController;
85
86    public MetroTubelineAssembler(final BindingID bindingId, MetroConfigName metroConfigName) {
87        this.bindingId = bindingId;
88        this.tubelineAssemblyController = new TubelineAssemblyController(metroConfigName);
89    }
90
91    TubelineAssemblyController getTubelineAssemblyController() {
92        return tubelineAssemblyController;
93    }
94
95    @NotNull
96    public Tube createClient(@NotNull ClientTubeAssemblerContext jaxwsContext) {
97        if (LOGGER.isLoggable(Level.FINER)) {
98            LOGGER.finer("Assembling client-side tubeline for WS endpoint: " + jaxwsContext.getAddress().getURI().toString());
99        }
100
101        DefaultClientTubelineAssemblyContext context = createClientContext(jaxwsContext);
102
103        Collection<TubeCreator> tubeCreators = tubelineAssemblyController.getTubeCreators(context);
104
105        for (TubeCreator tubeCreator : tubeCreators) {
106            tubeCreator.updateContext(context);
107        }
108
109        TubelineAssemblyDecorator decorator = TubelineAssemblyDecorator.composite(
110                ServiceFinder.find(TubelineAssemblyDecorator.class, context.getContainer()));
111
112        boolean first = true;
113        for (TubeCreator tubeCreator : tubeCreators) {
114            final MessageDumpingInfo msgDumpInfo = setupMessageDumping(tubeCreator.getMessageDumpPropertyBase(), Side.Client);
115
116            final Tube oldTubelineHead = context.getTubelineHead();
117            LoggingDumpTube afterDumpTube = null;
118            if (msgDumpInfo.dumpAfter) {
119                afterDumpTube = new LoggingDumpTube(msgDumpInfo.logLevel, LoggingDumpTube.Position.After, context.getTubelineHead());
120                context.setTubelineHead(afterDumpTube);
121            }
122
123            if (!context.setTubelineHead(decorator.decorateClient(tubeCreator.createTube(context), context))) { // no new tube has been created
124                if (afterDumpTube != null) {
125                    context.setTubelineHead(oldTubelineHead); // removing possible "after" message dumping tube
126                }
127            } else {
128                final String loggedTubeName = context.getTubelineHead().getClass().getName();
129                if (afterDumpTube != null) {
130                    afterDumpTube.setLoggedTubeName(loggedTubeName);
131                }
132
133                if (msgDumpInfo.dumpBefore) {
134                    final LoggingDumpTube beforeDumpTube = new LoggingDumpTube(msgDumpInfo.logLevel, LoggingDumpTube.Position.Before, context.getTubelineHead());
135                    beforeDumpTube.setLoggedTubeName(loggedTubeName);
136                    context.setTubelineHead(beforeDumpTube);
137                }
138            }
139
140            if (first) {
141                context.setTubelineHead(decorator.decorateClientTail(context.getTubelineHead(), context));
142                first = false;
143            }
144        }
145
146        return decorator.decorateClientHead(context.getTubelineHead(), context);
147    }
148
149    @NotNull
150    public Tube createServer(@NotNull ServerTubeAssemblerContext jaxwsContext) {
151        if (LOGGER.isLoggable(Level.FINER)) {
152            LOGGER.finer("Assembling endpoint tubeline for WS endpoint: " + jaxwsContext.getEndpoint().getServiceName() + "::" + jaxwsContext.getEndpoint().getPortName());
153        }
154
155        DefaultServerTubelineAssemblyContext context = createServerContext(jaxwsContext);
156
157        // FIXME endpoint URI for provider case
158        Collection<TubeCreator> tubeCreators = tubelineAssemblyController.getTubeCreators(context);
159        for (TubeCreator tubeCreator : tubeCreators) {
160            tubeCreator.updateContext(context);
161        }
162
163        TubelineAssemblyDecorator decorator = TubelineAssemblyDecorator.composite(
164                ServiceFinder.find(TubelineAssemblyDecorator.class, context.getEndpoint().getContainer()));
165
166        boolean first = true;
167        for (TubeCreator tubeCreator : tubeCreators) {
168            final MessageDumpingInfo msgDumpInfo = setupMessageDumping(tubeCreator.getMessageDumpPropertyBase(), Side.Endpoint);
169
170            final Tube oldTubelineHead = context.getTubelineHead();
171            LoggingDumpTube afterDumpTube = null;
172            if (msgDumpInfo.dumpAfter) {
173                afterDumpTube = new LoggingDumpTube(msgDumpInfo.logLevel, LoggingDumpTube.Position.After, context.getTubelineHead());
174                context.setTubelineHead(afterDumpTube);
175            }
176
177            if (!context.setTubelineHead(decorator.decorateServer(tubeCreator.createTube(context), context))) { // no new tube has been created
178                if (afterDumpTube != null) {
179                    context.setTubelineHead(oldTubelineHead); // removing possible "after" message dumping tube
180                }
181            } else {
182                final String loggedTubeName = context.getTubelineHead().getClass().getName();
183                if (afterDumpTube != null) {
184                    afterDumpTube.setLoggedTubeName(loggedTubeName);
185                }
186
187                if (msgDumpInfo.dumpBefore) {
188                    final LoggingDumpTube beforeDumpTube = new LoggingDumpTube(msgDumpInfo.logLevel, LoggingDumpTube.Position.Before, context.getTubelineHead());
189                    beforeDumpTube.setLoggedTubeName(loggedTubeName);
190                    context.setTubelineHead(beforeDumpTube);
191                }
192            }
193
194            if (first) {
195                context.setTubelineHead(decorator.decorateServerTail(context.getTubelineHead(), context));
196                first = false;
197            }
198        }
199
200        return decorator.decorateServerHead(context.getTubelineHead(), context);
201    }
202
203    private MessageDumpingInfo setupMessageDumping(String msgDumpSystemPropertyBase, Side side) {
204        boolean dumpBefore = false;
205        boolean dumpAfter = false;
206        Level logLevel = Level.INFO;
207
208        // checking common properties
209        Boolean value = getBooleanValue(COMMON_MESSAGE_DUMP_SYSTEM_PROPERTY_BASE);
210        if (value != null) {
211            dumpBefore = value.booleanValue();
212            dumpAfter = value.booleanValue();
213        }
214
215        value = getBooleanValue(COMMON_MESSAGE_DUMP_SYSTEM_PROPERTY_BASE + ".before");
216        dumpBefore = (value != null) ? value.booleanValue() : dumpBefore;
217
218        value = getBooleanValue(COMMON_MESSAGE_DUMP_SYSTEM_PROPERTY_BASE + ".after");
219        dumpAfter = (value != null) ? value.booleanValue() : dumpAfter;
220
221        Level levelValue = getLevelValue(COMMON_MESSAGE_DUMP_SYSTEM_PROPERTY_BASE + ".level");
222        if (levelValue != null) {
223            logLevel = levelValue;
224        }
225
226        // narrowing to proper communication side on common properties
227        value = getBooleanValue(COMMON_MESSAGE_DUMP_SYSTEM_PROPERTY_BASE + "." + side.toString());
228        if (value != null) {
229            dumpBefore = value.booleanValue();
230            dumpAfter = value.booleanValue();
231        }
232
233        value = getBooleanValue(COMMON_MESSAGE_DUMP_SYSTEM_PROPERTY_BASE + "." + side.toString() + ".before");
234        dumpBefore = (value != null) ? value.booleanValue() : dumpBefore;
235
236        value = getBooleanValue(COMMON_MESSAGE_DUMP_SYSTEM_PROPERTY_BASE + "." + side.toString() + ".after");
237        dumpAfter = (value != null) ? value.booleanValue() : dumpAfter;
238
239        levelValue = getLevelValue(COMMON_MESSAGE_DUMP_SYSTEM_PROPERTY_BASE + "." + side.toString() + ".level");
240        if (levelValue != null) {
241            logLevel = levelValue;
242        }
243
244
245        // checking general tube-specific properties
246        value = getBooleanValue(msgDumpSystemPropertyBase);
247        if (value != null) {
248            dumpBefore = value.booleanValue();
249            dumpAfter = value.booleanValue();
250        }
251
252        value = getBooleanValue(msgDumpSystemPropertyBase + ".before");
253        dumpBefore = (value != null) ? value.booleanValue() : dumpBefore;
254
255        value = getBooleanValue(msgDumpSystemPropertyBase + ".after");
256        dumpAfter = (value != null) ? value.booleanValue() : dumpAfter;
257
258        levelValue = getLevelValue(msgDumpSystemPropertyBase + ".level");
259        if (levelValue != null) {
260            logLevel = levelValue;
261        }
262
263        // narrowing to proper communication side on tube-specific properties
264        msgDumpSystemPropertyBase += "." + side.toString();
265
266        value = getBooleanValue(msgDumpSystemPropertyBase);
267        if (value != null) {
268            dumpBefore = value.booleanValue();
269            dumpAfter = value.booleanValue();
270        }
271
272        value = getBooleanValue(msgDumpSystemPropertyBase + ".before");
273        dumpBefore = (value != null) ? value.booleanValue() : dumpBefore;
274
275        value = getBooleanValue(msgDumpSystemPropertyBase + ".after");
276        dumpAfter = (value != null) ? value.booleanValue() : dumpAfter;
277
278        levelValue = getLevelValue(msgDumpSystemPropertyBase + ".level");
279        if (levelValue != null) {
280            logLevel = levelValue;
281        }
282
283        return new MessageDumpingInfo(dumpBefore, dumpAfter, logLevel);
284    }
285
286    private Boolean getBooleanValue(String propertyName) {
287        Boolean retVal = null;
288
289        String stringValue = System.getProperty(propertyName);
290        if (stringValue != null) {
291            retVal = Boolean.valueOf(stringValue);
292            LOGGER.fine(TubelineassemblyMessages.MASM_0018_MSG_LOGGING_SYSTEM_PROPERTY_SET_TO_VALUE(propertyName, retVal));
293        }
294
295        return retVal;
296    }
297
298    private Level getLevelValue(String propertyName) {
299        Level retVal = null;
300
301        String stringValue = System.getProperty(propertyName);
302        if (stringValue != null) {
303            // if value is not null => property is set, we will try to override the default logging level
304            LOGGER.fine(TubelineassemblyMessages.MASM_0018_MSG_LOGGING_SYSTEM_PROPERTY_SET_TO_VALUE(propertyName, stringValue));
305            try {
306                retVal = Level.parse(stringValue);
307            } catch (IllegalArgumentException ex) {
308                LOGGER.warning(TubelineassemblyMessages.MASM_0019_MSG_LOGGING_SYSTEM_PROPERTY_ILLEGAL_VALUE(propertyName, stringValue), ex);
309            }
310        }
311
312        return retVal;
313    }
314
315    // Extension point to change Tubeline Assembly behaviour: override if necessary ...
316    protected DefaultServerTubelineAssemblyContext createServerContext(ServerTubeAssemblerContext jaxwsContext) {
317        return new DefaultServerTubelineAssemblyContext(jaxwsContext);
318    }
319
320    // Extension point to change Tubeline Assembly behaviour: override if necessary ...
321    protected DefaultClientTubelineAssemblyContext createClientContext(ClientTubeAssemblerContext jaxwsContext) {
322        return new DefaultClientTubelineAssemblyContext(jaxwsContext);
323    }
324
325}
326