1 /*
2  * Copyright (c) 1997, 2012, 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 
26 package com.sun.xml.internal.ws.assembler;
27 
28 import com.sun.istack.internal.NotNull;
29 import com.sun.istack.internal.logging.Logger;
30 import com.sun.xml.internal.ws.api.BindingID;
31 import com.sun.xml.internal.ws.api.pipe.ClientTubeAssemblerContext;
32 import com.sun.xml.internal.ws.api.pipe.ServerTubeAssemblerContext;
33 import com.sun.xml.internal.ws.api.pipe.Tube;
34 import com.sun.xml.internal.ws.api.pipe.TubelineAssembler;
35 import com.sun.xml.internal.ws.assembler.dev.TubelineAssemblyDecorator;
36 import com.sun.xml.internal.ws.dump.LoggingDumpTube;
37 import com.sun.xml.internal.ws.resources.TubelineassemblyMessages;
38 import com.sun.xml.internal.ws.util.ServiceFinder;
39 
40 import java.util.Collection;
41 import java.util.logging.Level;
42 
43 /**
44 * TODO: Write some description here ...
45 *
46 * @author Miroslav Kos (miroslav.kos at oracle.com)
47 */
48 public 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 
Side(String name)59         private Side(String name) {
60             this.name = name;
61         }
62 
63         @Override
toString()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 
MessageDumpingInfo(boolean dumpBefore, boolean dumpAfter, Level logLevel)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 
MetroTubelineAssembler(final BindingID bindingId, MetroConfigName metroConfigName)86     public MetroTubelineAssembler(final BindingID bindingId, MetroConfigName metroConfigName) {
87         this.bindingId = bindingId;
88         this.tubelineAssemblyController = new TubelineAssemblyController(metroConfigName);
89     }
90 
getTubelineAssemblyController()91     TubelineAssemblyController getTubelineAssemblyController() {
92         return tubelineAssemblyController;
93     }
94 
95     @NotNull
createClient(@otNull ClientTubeAssemblerContext jaxwsContext)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
createServer(@otNull ServerTubeAssemblerContext jaxwsContext)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 
setupMessageDumping(String msgDumpSystemPropertyBase, Side side)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 
getBooleanValue(String propertyName)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 
getLevelValue(String propertyName)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 ...
createServerContext(ServerTubeAssemblerContext jaxwsContext)316     protected DefaultServerTubelineAssemblyContext createServerContext(ServerTubeAssemblerContext jaxwsContext) {
317         return new DefaultServerTubelineAssemblyContext(jaxwsContext);
318     }
319 
320     // Extension point to change Tubeline Assembly behaviour: override if necessary ...
createClientContext(ClientTubeAssemblerContext jaxwsContext)321     protected DefaultClientTubelineAssemblyContext createClientContext(ClientTubeAssemblerContext jaxwsContext) {
322         return new DefaultClientTubelineAssemblyContext(jaxwsContext);
323     }
324 
325 }
326