1
2
3
4
5
6
7 package org.mule.module.xml.expression;
8
9 import org.mule.api.MuleContext;
10 import org.mule.api.MuleMessage;
11 import org.mule.api.MuleRuntimeException;
12 import org.mule.api.context.MuleContextAware;
13 import org.mule.api.context.notification.MuleContextNotificationListener;
14 import org.mule.api.expression.ExpressionEvaluator;
15 import org.mule.api.expression.ExpressionRuntimeException;
16 import org.mule.api.lifecycle.Disposable;
17 import org.mule.api.lifecycle.Initialisable;
18 import org.mule.api.lifecycle.InitialisationException;
19 import org.mule.api.registry.RegistrationException;
20 import org.mule.config.i18n.CoreMessages;
21 import org.mule.context.notification.MuleContextNotification;
22 import org.mule.module.xml.i18n.XmlMessages;
23 import org.mule.module.xml.util.NamespaceManager;
24
25 import java.util.ArrayList;
26 import java.util.Iterator;
27 import java.util.List;
28 import java.util.Map;
29 import java.util.WeakHashMap;
30
31 import org.dom4j.Document;
32 import org.jaxen.JaxenException;
33 import org.jaxen.XPath;
34 import org.mule.transformer.types.DataTypeFactory;
35
36
37
38
39
40 public abstract class AbstractXPathExpressionEvaluator implements ExpressionEvaluator, Initialisable, Disposable, MuleContextAware
41 {
42 private Map<String, XPath> cache = new WeakHashMap<String, XPath>(8);
43
44 private MuleContext muleContext;
45 private NamespaceManager namespaceManager;
46
47 public void setMuleContext(MuleContext context)
48 {
49 this.muleContext = context;
50
51 }
52
53 public void initialise() throws InitialisationException
54 {
55 try
56 {
57
58
59
60
61
62
63
64
65 this.muleContext.registerListener(new MuleContextNotificationListener<MuleContextNotification>(){
66
67 public void onNotification(MuleContextNotification notification)
68 {
69
70 if (MuleContextNotification.CONTEXT_STARTING == notification.getAction())
71 {
72 try
73 {
74 namespaceManager = muleContext.getRegistry().lookupObject(NamespaceManager.class);
75 }
76 catch (RegistrationException e)
77 {
78 throw new RuntimeException(e);
79 }
80 }
81 }
82 });
83 }
84 catch (Throwable t)
85 {
86 throw new InitialisationException(t, this);
87 }
88 }
89
90 public void inject() throws Exception
91 {
92 try
93 {
94 namespaceManager = muleContext.getRegistry().lookupObject(NamespaceManager.class);
95 }
96 catch (RegistrationException e)
97 {
98 throw new ExpressionRuntimeException(CoreMessages.failedToLoad("NamespaceManager"), e);
99 }
100 }
101
102
103 public Object evaluate(String expression, MuleMessage message)
104 {
105 try
106 {
107 Object payload = message.getPayload();
108
109 if(payload instanceof String)
110 {
111 payload = message.getPayload(DataTypeFactory.create(Document.class));
112 }
113
114 List<?> result;
115
116
117
118
119 XPath xpath = getXPath(expression, payload);
120 synchronized (xpath)
121 {
122 result = xpath.selectNodes(payload);
123 }
124
125 result = extractResultsFromNodes(result);
126 if(result.size()==1)
127 {
128 return result.get(0);
129 }
130 else if(result.size()==0)
131 {
132 return null;
133 }
134 else
135 {
136 return result;
137 }
138 }
139 catch (Exception e)
140 {
141 throw new MuleRuntimeException(XmlMessages.failedToProcessXPath(expression), e);
142 }
143 }
144
145 protected void addNamespaces(NamespaceManager manager, XPath xpath)
146 {
147 for (Iterator<?> iterator = manager.getNamespaces().entrySet().iterator(); iterator.hasNext();)
148 {
149 Map.Entry<?, ?> entry = (Map.Entry<?, ?>)iterator.next();
150 try
151 {
152 xpath.addNamespace(entry.getKey().toString(), entry.getValue().toString());
153 }
154 catch (JaxenException e)
155 {
156 throw new ExpressionRuntimeException(XmlMessages.failedToRegisterNamespace(entry.getKey().toString(), entry.getValue().toString()));
157 }
158 }
159 }
160
161
162 public final void setName(String name)
163 {
164 throw new UnsupportedOperationException("setName");
165 }
166
167
168
169
170
171
172 protected XPath getXPath(String expression, Object object) throws JaxenException
173 {
174 String xPathCacheKey = expression + getXPathClassName(object);
175 XPath xpath = cache.get(xPathCacheKey);
176 if(xpath==null)
177 {
178 xpath = createXPath(expression, object);
179 synchronized (xpath)
180 {
181 if(namespaceManager!=null)
182 {
183 addNamespaces(namespaceManager, xpath);
184 }
185 }
186 cache.put(xPathCacheKey, xpath);
187 }
188 return xpath;
189 }
190
191 protected String getXPathClassName(Object object)
192 {
193 return getClass().getName();
194 }
195
196 protected abstract XPath createXPath(String expression, Object object) throws JaxenException;
197
198 protected List<?> extractResultsFromNodes(List<?> results)
199 {
200 if (results == null)
201 {
202 return null;
203 }
204 List<Object> newResults = new ArrayList<Object>(results.size());
205 for (Object o : results)
206 {
207 newResults.add(extractResultFromNode(o));
208 }
209 return newResults;
210 }
211
212
213
214
215
216
217 public void dispose()
218 {
219 cache.clear();
220 }
221
222 public NamespaceManager getNamespaceManager()
223 {
224 return namespaceManager;
225 }
226
227 public void setNamespaceManager(NamespaceManager namespaceManager)
228 {
229 this.namespaceManager = namespaceManager;
230 }
231
232 public MuleContext getMuleContext()
233 {
234 return muleContext;
235 }
236
237 protected abstract Object extractResultFromNode(Object result);
238 }