View Javadoc

1   package net.sf.snmpadaptor4j.core.mapping;
2   
3   import java.net.URL;
4   import java.util.ArrayList;
5   import java.util.HashMap;
6   import java.util.Iterator;
7   import java.util.List;
8   import java.util.Map;
9   import javax.management.MBeanAttributeInfo;
10  import javax.management.ObjectName;
11  import javax.xml.bind.JAXBContext;
12  import javax.xml.bind.JAXBElement;
13  import javax.xml.bind.Unmarshaller;
14  import net.sf.snmpadaptor4j.core.mapping.jaxb.GenericTrap;
15  import net.sf.snmpadaptor4j.core.mapping.jaxb.MBean;
16  import net.sf.snmpadaptor4j.core.mapping.jaxb.MBeanAttribute;
17  import net.sf.snmpadaptor4j.core.mapping.jaxb.MBeanNotifications;
18  import net.sf.snmpadaptor4j.core.mapping.jaxb.Mapping;
19  import net.sf.snmpadaptor4j.core.mapping.jaxb.SpecificTrap;
20  import net.sf.snmpadaptor4j.core.mapping.jaxb.TrapEnterprise;
21  import net.sf.snmpadaptor4j.core.mapping.jaxb.TrapUserData;
22  import net.sf.snmpadaptor4j.core.mapping.jaxb.TrapUserDataEntry;
23  import net.sf.snmpadaptor4j.core.mapping.jaxb.TrapUserDataMap;
24  import net.sf.snmpadaptor4j.core.mapping.jaxb.TrapVariableBindings;
25  import net.sf.snmpadaptor4j.object.SnmpDataType;
26  import net.sf.snmpadaptor4j.object.GenericSnmpTrapType;
27  import net.sf.snmpadaptor4j.object.SnmpOid;
28  
29  /**
30   * Parser of SNMP mapping file (XML).
31   * @author <a href="http://fr.linkedin.com/in/jpminetti/">Jean-Philippe MINETTI</a>
32   */
33  public final class XmlMappingParser {
34  
35  	/**
36  	 * {@link URL} to the SNMP mapping file.
37  	 */
38  	private final URL url;
39  
40  	/**
41  	 * JAXB representation of the SNMP mapping file.
42  	 */
43  	private final JAXBElement<Mapping> jaxbElement;
44  
45  	/**
46  	 * Creates and returns a new instance of {@link XmlMappingParser}.
47  	 * @param url {@link URL} to the SNMP mapping file.
48  	 * @return New instance of {@link XmlMappingParser}.
49  	 * @throws Exception Exception if an error occurred.
50  	 */
51  	public static XmlMappingParser newInstance (final URL url) throws Exception {
52  		final JAXBContext jaxbContext = JAXBContext.newInstance(Mapping.class.getPackage().getName());
53  		final Unmarshaller unmarshaller = jaxbContext.createUnmarshaller();
54  		@SuppressWarnings("unchecked")
55  		final JAXBElement<Mapping> jaxbElement = (JAXBElement<Mapping>) unmarshaller.unmarshal(url);
56  		return new XmlMappingParser(url, jaxbElement);
57  	}
58  
59  	/**
60  	 * Constructor.
61  	 * @param url {@link URL} to the SNMP mapping file.
62  	 * @param jaxbElement JAXB representation of the SNMP mapping file.
63  	 */
64  	private XmlMappingParser (final URL url, final JAXBElement<Mapping> jaxbElement) {
65  		super();
66  		this.url = url;
67  		this.jaxbElement = jaxbElement;
68  	}
69  
70  	/**
71  	 * Finds a base OID of a MBean instance in the mapping.
72  	 * @param mBeanName MBean name.
73  	 * @param rootOidMap Map of root OIDs where the attributes of the application will stay.
74  	 * @param defaultRootOid Default root OID containing the attributes of the current application.
75  	 * @param mainDefaultRootOid Default root OID containing the attributes of the main application (must not be <code>NULL</code>).
76  	 * @return Base OID found (can be <code>NULL</code>).
77  	 */
78  	public String findBaseOid (final ObjectName mBeanName, final Map<String, String> rootOidMap, final String defaultRootOid, final String mainDefaultRootOid) {
79  		String baseOid = null;
80  		final Mapping mapping = this.jaxbElement.getValue();
81  		if (mapping.getMbeans() != null) {
82  			final Iterator<MBean> mBeanIterator = mapping.getMbeans().getMbean().iterator();
83  			final String desiredName = mBeanName.toString();
84  			MBean mBean;
85  			while (mBeanIterator.hasNext() && (baseOid == null)) {
86  				mBean = mBeanIterator.next();
87  				if (mBean.getName().equals(desiredName)) {
88  					if (mBean.getRoot() != null) {
89  						baseOid = rootOidMap.get(mBean.getRoot());
90  					}
91  					if (baseOid == null) {
92  						baseOid = defaultRootOid;
93  					}
94  					if (baseOid == null) {
95  						baseOid = mainDefaultRootOid;
96  					}
97  					baseOid = baseOid + "." + mBean.getOid();
98  				}
99  			}
100 		}
101 		return baseOid;
102 	}
103 
104 	/**
105 	 * Creates and returns the list of mapping for access to each attribute of an MBean.
106 	 * @param mBeanAttributeInfoMap Map of informations on each MBean attribute.
107 	 * @param classLoader {@link ClassLoader} where the MBean has been created.
108 	 * @param baseOid Base OID of MBean instance.
109 	 * @return List of mapping for access to each attribute of an MBean (never <code>NULL</code>).
110 	 * @throws Exception Exception if an error occurred.
111 	 */
112 	public List<MBeanAttributeMapping> newMBeanAttributeMappingList (final Map<String, MBeanAttributeInfo> mBeanAttributeInfoMap, final ClassLoader classLoader,
113 			final String baseOid) throws Exception {
114 		final List<MBeanAttributeMapping> mappingList = new ArrayList<MBeanAttributeMapping>();
115 		final Iterator<MBeanAttribute> attributeIterator = this.jaxbElement.getValue().getAttributes().getAttribute().iterator();
116 		MBeanAttribute attribute;
117 		String attributeName;
118 		MBeanAttributeInfo mBeanAttributeInfo;
119 		SnmpOid oid;
120 		SnmpDataType snmpDataType;
121 		Class<?> jmxDataType;
122 		boolean readable;
123 		boolean writable;
124 		while (attributeIterator.hasNext()) {
125 			attribute = attributeIterator.next();
126 
127 			// Property name & info
128 			attributeName = attribute.getName().substring(0, 1).toUpperCase() + attribute.getName().substring(1);
129 			mBeanAttributeInfo = mBeanAttributeInfoMap.get(attributeName);
130 
131 			// OID
132 			oid = SnmpOid.newInstance(baseOid, attribute.getNode(), 0);
133 
134 			// snmpDataType
135 			snmpDataType = SnmpDataType.valueOf(attribute.getType().value());
136 
137 			// jmxDataType
138 			jmxDataType = toClass(classLoader, mBeanAttributeInfo.getType());
139 
140 			// readable
141 			readable = (mBeanAttributeInfo.isReadable() && !attribute.isDisabled());
142 
143 			// writable
144 			writable = (readable && mBeanAttributeInfo.isWritable() && attribute.isWritable());
145 
146 			mappingList.add(new MBeanAttributeMapping(oid, attributeName, snmpDataType, jmxDataType, readable, writable));
147 		}
148 		return mappingList;
149 	}
150 
151 	/**
152 	 * Converts a class name to its instance.
153 	 * @param classLoader {@link ClassLoader} where the MBean has been created.
154 	 * @param className Class name.
155 	 * @return Class instance.
156 	 * @throws Exception Exception if an error occurred.
157 	 */
158 	private Class<?> toClass (final ClassLoader classLoader, final String className) throws Exception {
159 		Class<?> result;
160 		if (byte.class.getName().equals(className)) {
161 			result = byte.class;
162 		}
163 		else if (short.class.getName().equals(className)) {
164 			result = short.class;
165 		}
166 		else if (int.class.getName().equals(className)) {
167 			result = int.class;
168 		}
169 		else if (boolean.class.getName().equals(className)) {
170 			result = boolean.class;
171 		}
172 		else if (long.class.getName().equals(className)) {
173 			result = long.class;
174 		}
175 		else if (byte[].class.getName().equals(className)) {
176 			result = byte[].class;
177 		}
178 		else if (short[].class.getName().equals(className)) {
179 			result = short[].class;
180 		}
181 		else if (int[].class.getName().equals(className)) {
182 			result = int[].class;
183 		}
184 		else if (long[].class.getName().equals(className)) {
185 			result = long[].class;
186 		}
187 		else {
188 			result = classLoader.loadClass(className);
189 		}
190 		return result;
191 	}
192 
193 	/**
194 	 * Creates and returns the map of mapping to build SNMP traps from JMX notifications for each notification type.
195 	 * @param baseOid Base OID of MBean instance.
196 	 * @return Map of mapping to build SNMP traps from the JMX notifications for each notification type (never <code>NULL</code>).
197 	 */
198 	public Map<String, SnmpTrapMapping> newSnmpTrapMappingMap (final String baseOid) {
199 		final Map<String, SnmpTrapMapping> trapMapping = new HashMap<String, SnmpTrapMapping>();
200 		final MBeanNotifications notifications = this.jaxbElement.getValue().getNotifications();
201 		if (notifications != null) {
202 			final Map<String, DataMapTrapMapping> dataMapMappingMap = newDataMapTrapMappingMap(baseOid, notifications.getVariableBindings());
203 			final DataMapTrapMapping defaultDataMapMapping = newDefaultDataMapTrapMapping(baseOid, notifications.getVariableBindings());
204 			DataMapTrapMapping dataMapMapping;
205 			SnmpOid source;
206 			GenericSnmpTrapType genericType;
207 			for (final TrapEnterprise enterprise : notifications.getEnterprise()) {
208 				for (final GenericTrap trap : enterprise.getGenericTrap()) {
209 					dataMapMapping = findDataMapTrapMapping(dataMapMappingMap, defaultDataMapMapping, enterprise, trap.getUserdata());
210 					source = SnmpOid.newInstance(baseOid, enterprise.getNode(), 0);
211 					genericType = GenericSnmpTrapType.valueOf(trap.getCode().value());
212 					trapMapping.put(trap.getNotifType(), new GenericSnmpTrapMapping(source, dataMapMapping, genericType));
213 				}
214 				for (final SpecificTrap trap : enterprise.getSpecificTrap()) {
215 					dataMapMapping = findDataMapTrapMapping(dataMapMappingMap, defaultDataMapMapping, enterprise, trap.getUserdata());
216 					source = SnmpOid.newInstance(baseOid, enterprise.getNode(), 0);
217 					trapMapping.put(trap.getNotifType(), new SpecificSnmpTrapMapping(source, dataMapMapping, trap.getCode()));
218 				}
219 			}
220 		}
221 		return trapMapping;
222 	}
223 
224 	/**
225 	 * Find a mapping to build the <code>dataMap</code> field of {@link net.sf.snmpadaptor4j.object.SnmpTrap SnmpTrap} by its name.
226 	 * @param dataMapMappingMap Map of mapping to build the <code>dataMap</code> field of {@link net.sf.snmpadaptor4j.object.SnmpTrap SnmpTrap} from JMX
227 	 *            notifications (must not be <code>NULL</code>).
228 	 * @param defaultDataMapMapping Default mapping to build the <code>dataMap</code> field of {@link net.sf.snmpadaptor4j.object.SnmpTrap SnmpTrap} from JMX
229 	 *            notifications (must not be <code>NULL</code>).
230 	 * @param enterprise Represents the contents of <code>enterprise</code> tag of XML file.
231 	 * @param userDataName Name of mapping to find for build the <code>dataMap</code> field of {@link net.sf.snmpadaptor4j.object.SnmpTrap SnmpTrap}.
232 	 * @return Mapping found to build the <code>dataMap</code> field of {@link net.sf.snmpadaptor4j.object.SnmpTrap SnmpTrap}.
233 	 */
234 	private DataMapTrapMapping findDataMapTrapMapping (final Map<String, DataMapTrapMapping> dataMapMappingMap, final DataMapTrapMapping defaultDataMapMapping,
235 			final TrapEnterprise enterprise, final String userDataName) {
236 		DataMapTrapMapping dataMapMapping = null;
237 		String dataMapMappingName = (userDataName != null ? userDataName : enterprise.getUserdata());
238 		if (dataMapMappingName != null) {
239 			dataMapMapping = dataMapMappingMap.get(dataMapMappingName);
240 		}
241 		if (dataMapMapping == null) {
242 			dataMapMapping = defaultDataMapMapping;
243 		}
244 		return dataMapMapping;
245 	}
246 
247 	/**
248 	 * Creates and returns the map of mapping to build the <code>dataMap</code> field of {@link net.sf.snmpadaptor4j.object.SnmpTrap SnmpTrap} from JMX
249 	 * notifications.
250 	 * @param baseOid Base OID of MBean instance.
251 	 * @param variableBindings Represents the contents of <code>variable-bindings</code> tag of XML file.
252 	 * @return Map of mapping to build the <code>dataMap</code> field of {@link net.sf.snmpadaptor4j.object.SnmpTrap SnmpTrap} from JMX notifications (never
253 	 *         <code>NULL</code>).
254 	 */
255 	private Map<String, DataMapTrapMapping> newDataMapTrapMappingMap (final String baseOid, final TrapVariableBindings variableBindings) {
256 		final Map<String, DataMapTrapMapping> dataMapMappingMap = new HashMap<String, DataMapTrapMapping>();
257 		if (variableBindings != null) {
258 			final SnmpOid sequenceNumberOid = (variableBindings.getSequenceNumber() != null ? SnmpOid.newInstance(baseOid, variableBindings.getSequenceNumber()
259 					.getNode(), 0) : null);
260 			final SnmpOid messageOid = (variableBindings.getMessage() != null ? SnmpOid.newInstance(baseOid, variableBindings.getMessage().getNode(), 0) : null);
261 			final boolean hasSystemInfo = variableBindings.isSystemInfo();
262 			DataMapTrapMapping dataMapMapping;
263 			SnmpDataType userDataType;
264 			SnmpOid userDataOid;
265 			for (final TrapUserData userData : variableBindings.getUserdata()) {
266 				userDataType = SnmpDataType.valueOf(userData.getType().value());
267 				userDataOid = SnmpOid.newInstance(baseOid, userData.getNode(), 0);
268 				dataMapMapping = new SimpleDataMapTrapMapping(sequenceNumberOid, messageOid, hasSystemInfo, userDataType, userDataOid);
269 				dataMapMappingMap.put(userData.getName(), dataMapMapping);
270 			}
271 			MapDataMapTrapMapping mapDataMapMapping;
272 			for (final TrapUserDataMap userDataMap : variableBindings.getUserdataMap()) {
273 				mapDataMapMapping = new MapDataMapTrapMapping(sequenceNumberOid, messageOid, hasSystemInfo);
274 				for (final TrapUserDataEntry entry : userDataMap.getEntry()) {
275 					userDataType = SnmpDataType.valueOf(entry.getType().value());
276 					userDataOid = SnmpOid.newInstance(baseOid, entry.getNode(), 0);
277 					mapDataMapMapping.addUserDataEntry(entry.getKey(), userDataType, userDataOid);
278 				}
279 				dataMapMappingMap.put(userDataMap.getName(), mapDataMapMapping);
280 			}
281 		}
282 		return dataMapMappingMap;
283 	}
284 
285 	/**
286 	 * Creates and returns the default mapping to build the <code>dataMap</code> field of {@link net.sf.snmpadaptor4j.object.SnmpTrap SnmpTrap} from JMX
287 	 * notifications.
288 	 * @param baseOid Base OID of MBean instance.
289 	 * @param variableBindings Represents the contents of <code>variable-bindings</code> tag of XML file.
290 	 * @return Default mapping to build the <code>dataMap</code> field of {@link net.sf.snmpadaptor4j.object.SnmpTrap SnmpTrap} from JMX notifications (never
291 	 *         <code>NULL</code>).
292 	 */
293 	private DefaultDataMapTrapMapping newDefaultDataMapTrapMapping (final String baseOid, final TrapVariableBindings variableBindings) {
294 		DefaultDataMapTrapMapping defaultDataMapMapping;
295 		if (variableBindings != null) {
296 			final SnmpOid sequenceNumberOid = (variableBindings.getSequenceNumber() != null ? SnmpOid.newInstance(baseOid, variableBindings.getSequenceNumber()
297 					.getNode(), 0) : null);
298 			final SnmpOid messageOid = (variableBindings.getMessage() != null ? SnmpOid.newInstance(baseOid, variableBindings.getMessage().getNode(), 0) : null);
299 			final boolean hasSystemInfo = variableBindings.isSystemInfo();
300 			defaultDataMapMapping = new DefaultDataMapTrapMapping(sequenceNumberOid, messageOid, hasSystemInfo);
301 		}
302 		else {
303 			defaultDataMapMapping = new DefaultDataMapTrapMapping(null, null, false);
304 		}
305 		return defaultDataMapMapping;
306 	}
307 
308 	/*
309 	 * {@inheritDoc}
310 	 * @see java.lang.Object#toString()
311 	 */
312 	@Override
313 	public String toString () {
314 		return "XmlMappingParser[" + this.url + "]";
315 	}
316 
317 }