1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package edu.internet2.middleware.grouper.ws.rest.contentType;
20
21 import java.io.Writer;
22 import java.util.Map;
23
24 import org.apache.commons.logging.Log;
25 import org.apache.commons.logging.LogFactory;
26
27 import com.thoughtworks.xstream.XStream;
28 import com.thoughtworks.xstream.io.json.JettisonMappedXmlDriver;
29 import com.thoughtworks.xstream.io.xml.CompactWriter;
30 import com.thoughtworks.xstream.io.xml.XppDriver;
31 import com.thoughtworks.xstream.mapper.MapperWrapper;
32
33 import edu.internet2.middleware.grouper.misc.GrouperVersion;
34 import edu.internet2.middleware.grouper.util.GrouperUtil;
35 import edu.internet2.middleware.grouper.ws.GrouperWsConfig;
36 import edu.internet2.middleware.grouper.ws.coresoap.WsSubject;
37 import edu.internet2.middleware.grouper.ws.rest.GrouperRestInvalidRequest;
38 import edu.internet2.middleware.grouper.ws.rest.WsRestClassLookup;
39 import edu.internet2.middleware.grouper.ws.rest.json.JsonConverter;
40 import edu.internet2.middleware.grouper.ws.util.GrouperServiceUtils;
41 import edu.internet2.middleware.grouper.ws.util.GrouperWsVersionUtils;
42
43
44
45
46 public enum WsRestResponseContentType {
47
48
49 xml {
50
51
52
53
54
55 @Override
56 public String getContentType() {
57 return GrouperWsConfig.retrieveConfig().propertyValueString("ws.restResponseContentType.xml", "application/xml");
58 }
59
60
61
62
63
64
65 @Override
66 public void writeString(Object object, Writer writer) {
67 XStream xstream = xstream(false);
68
69 xstream.marshal(object, new CompactWriter(writer));
70 }
71
72
73
74
75
76
77 @Override
78 public Object parseString(String input) {
79 return WsRestRequestContentType.xml.parseString(input, new StringBuilder());
80 }
81
82 },
83
84 json {
85
86
87
88
89
90 @Override
91 public String getContentType() {
92 return GrouperWsConfig.retrieveConfig().propertyValueString("ws.restResponseContentType.json", "application/json");
93 }
94
95
96
97
98
99
100 @Override
101 public void writeString(Object object, Writer writer) {
102 JsonConverter jsonConverter = WsRestRequestContentType.jsonConverter();
103 try {
104 jsonConverter.convertToJson(object, writer);
105 } catch (RuntimeException re) {
106 LOG.error("Error converting json object with converter: "
107 + GrouperUtil.className(jsonConverter) + ", " + GrouperUtil.className(object));
108 throw new RuntimeException("Error converting json object with converter: " + GrouperUtil.className(jsonConverter)
109 + ", " + GrouperUtil.className(object), re);
110 }
111 }
112
113
114
115
116
117
118 @Override
119 public Object parseString(String input) {
120 return WsRestRequestContentType.json.parseString(input, new StringBuilder());
121 }
122
123 };
124
125
126
127
128
129
130 public abstract void writeString(Object object, Writer writer);
131
132
133 private static final Log LOG = GrouperUtil.getLog(WsRestResponseContentType.class);
134
135
136
137
138
139
140 public abstract Object parseString(String input);
141
142
143
144
145
146 public abstract String getContentType();
147
148
149
150
151
152
153 public static XStream xstream(boolean isJson) {
154
155 XStream xstream = null;
156
157 boolean ignoreExtraneousFields = GrouperWsConfig.retrieveConfig().propertyValueBoolean("ws.ignoreExtraneousXmlFieldsRest", false);
158
159 if (ignoreExtraneousFields) {
160 xstream = new XStream(isJson ? new JettisonMappedXmlDriver() : new XppDriver()) {
161
162
163
164
165
166 @Override
167 protected MapperWrapper wrapMapper(MapperWrapper next) {
168 return new MapperWrapper(next) {
169
170
171
172
173
174 @SuppressWarnings("unchecked")
175 @Override
176 public boolean shouldSerializeMember(Class definedIn, String fieldName) {
177 boolean definedInNotObject = definedIn != Object.class;
178 if (definedInNotObject) {
179 return super.shouldSerializeMember(definedIn, fieldName);
180 }
181
182 LOG.info("Cant find field: " + fieldName);
183 return false;
184 }
185
186 };
187 }
188 };
189
190 } else {
191 xstream = isJson ? new XStream(new JettisonMappedXmlDriver()) : new XStream();
192 }
193
194
195 String fieldsToOmit = GrouperWsConfig.retrieveConfig().propertyValueString("ws.omitXmlPropertiesRest");
196 if (!GrouperUtil.isBlank(fieldsToOmit)) {
197 String[] fieldsToOmitList = GrouperUtil.splitTrim(fieldsToOmit, ",");
198 for (String fieldToOmit: fieldsToOmitList) {
199 if (!GrouperUtil.isBlank(fieldToOmit)) {
200 try {
201 int dotIndex = fieldToOmit.lastIndexOf('.');
202 String className = fieldToOmit.substring(0, dotIndex);
203 String propertyName = fieldToOmit.substring(dotIndex+1, fieldToOmit.length());
204 Class<?> theClass = GrouperUtil.forName(className);
205 xstream.omitField(theClass, propertyName);
206 } catch (Exception e) {
207 throw new RuntimeException("Problem with ws.omitXmlPropertiesRest: " + fieldsToOmit + ", " + e.getMessage(), e);
208 }
209 }
210 }
211 }
212 GrouperVersion clientVersion = GrouperWsVersionUtils.retrieveCurrentClientVersion();
213 if (clientVersion != null && clientVersion.lessThanArg(GrouperVersion.valueOfIgnoreCase("v1_4_000"))) {
214 xstream.omitField(WsSubject.class, "identifierLookup");
215 }
216
217
218 xstream.setMode(XStream.NO_REFERENCES);
219 xstream.autodetectAnnotations(true);
220 Map<String, Class<?>> aliasClassMap = WsRestClassLookup.getAliasClassMap();
221 for (String key : aliasClassMap.keySet()) {
222 xstream.alias(key, aliasClassMap.get(key));
223 }
224
225 xstream.allowTypes(aliasClassMap.values().toArray(new Class[0]));
226
227 return xstream;
228 }
229
230
231
232
233
234
235
236
237
238 public static WsRestResponseContentType valueOfIgnoreCase(String string,
239 boolean exceptionOnNotFound) throws GrouperRestInvalidRequest {
240 return GrouperServiceUtils.enumValueOfIgnoreCase(WsRestResponseContentType.class,
241 string, exceptionOnNotFound);
242 }
243
244 }