blob: 43379d918cc635f600baf50d7e83dd2589f1b5f2 [file] [log] [blame]
J. Duke319a3b92007-12-01 00:00:00 +00001/*
2 * Copyright 2003-2006 Sun Microsystems, Inc. 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. Sun designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
22 * CA 95054 USA or visit www.sun.com if you need additional information or
23 * have any questions.
24 */
25
26package sun.management.snmp;
27
28import com.sun.jmx.snmp.daemon.SnmpAdaptorServer;
29import com.sun.jmx.snmp.InetAddressAcl;
30import com.sun.jmx.snmp.IPAcl.SnmpAcl;
31import sun.management.snmp.jvmmib.JVM_MANAGEMENT_MIB;
32import sun.management.snmp.jvminstr.JVM_MANAGEMENT_MIB_IMPL;
33import sun.management.snmp.jvminstr.NotificationTarget;
34import sun.management.snmp.jvminstr.NotificationTargetImpl;
35import sun.management.snmp.util.MibLogger;
36import sun.management.snmp.util.JvmContextFactory;
37
38import sun.management.Agent;
39import sun.management.AgentConfigurationError;
40import static sun.management.AgentConfigurationError.*;
41import sun.management.FileSystem;
42
43import java.util.List;
44import java.util.ArrayList;
45import java.util.Enumeration;
46import java.util.Properties;
47
48import java.io.IOException;
49import java.io.File;
50import java.io.FileInputStream;
51
52import java.net.InetAddress;
53import java.net.UnknownHostException;
54
55/**
56 * This class initializes and starts the SNMP Adaptor for JSR 163 SNMP
57 * Monitoring.
58 **/
59public final class AdaptorBootstrap {
60
61 private static final MibLogger log = new MibLogger(AdaptorBootstrap.class);
62
63 /**
64 * Default values for SNMP configuration properties.
65 **/
66 public static interface DefaultValues {
67 public static final String PORT="161";
68 public static final String CONFIG_FILE_NAME="management.properties";
69 public static final String TRAP_PORT="162";
70 public static final String USE_ACL="true";
71 public static final String ACL_FILE_NAME="snmp.acl";
72 public static final String BIND_ADDRESS="localhost";
73 }
74
75 /**
76 * Names of SNMP configuration properties.
77 **/
78 public static interface PropertyNames {
79 public static final String PORT="com.sun.management.snmp.port";
80 public static final String CONFIG_FILE_NAME=
81 "com.sun.management.config.file";
82 public static final String TRAP_PORT=
83 "com.sun.management.snmp.trap";
84 public static final String USE_ACL=
85 "com.sun.management.snmp.acl";
86 public static final String ACL_FILE_NAME=
87 "com.sun.management.snmp.acl.file";
88 public static final String BIND_ADDRESS=
89 "com.sun.management.snmp.interface";
90 }
91
92 /**
93 * We keep a reference - so that we can possibly call
94 * terminate(). As of now, terminate() is only called by unit tests
95 * (makes it possible to run several testcases sequentially in the
96 * same JVM).
97 **/
98 private SnmpAdaptorServer adaptor;
99 private JVM_MANAGEMENT_MIB_IMPL jvmmib;
100
101 private AdaptorBootstrap(SnmpAdaptorServer snmpas,
102 JVM_MANAGEMENT_MIB_IMPL mib) {
103 jvmmib = mib;
104 adaptor = snmpas;
105 }
106
107 /**
108 * Compute the full path name for a default file.
109 * @param basename basename (with extension) of the default file.
110 * @return ${JRE}/lib/management/${basename}
111 **/
112 private static String getDefaultFileName(String basename) {
113 final String fileSeparator = File.separator;
114 return System.getProperty("java.home") + fileSeparator + "lib" +
115 fileSeparator + "management" + fileSeparator + basename;
116 }
117
118 /**
119 * Retrieve the Trap Target List from the ACL file.
120 **/
121 private static List<NotificationTarget> getTargetList(InetAddressAcl acl,
122 int defaultTrapPort) {
123 final ArrayList<NotificationTarget> result =
124 new ArrayList<NotificationTarget>();
125 if (acl != null) {
126 if (log.isDebugOn())
127 log.debug("getTargetList",Agent.getText("jmxremote.AdaptorBootstrap.getTargetList.processing"));
128
129 final Enumeration td=acl.getTrapDestinations();
130 for (; td.hasMoreElements() ;) {
131 final InetAddress targetAddr = (InetAddress)td.nextElement();
132 final Enumeration tc =
133 acl.getTrapCommunities(targetAddr);
134 for (;tc.hasMoreElements() ;) {
135 final String community = (String) tc.nextElement();
136 final NotificationTarget target =
137 new NotificationTargetImpl(targetAddr,
138 defaultTrapPort,
139 community);
140 if (log.isDebugOn())
141 log.debug("getTargetList",
142 Agent.getText("jmxremote.AdaptorBootstrap.getTargetList.adding",
143 target.toString()));
144 result.add(target);
145 }
146 }
147 }
148 return result;
149 }
150
151 /**
152 * Initializes and starts the SNMP Adaptor Server.
153 * If the com.sun.management.snmp.port property is not defined,
154 * simply return. Otherwise, attempts to load the config file, and
155 * then calls {@link #initialize(java.lang.String, java.util.Properties)}.
156 *
157 **/
158 public static synchronized AdaptorBootstrap initialize() {
159
160 // Load a new properties
161 final Properties props = Agent.loadManagementProperties();
162 if (props == null) return null;
163
164 final String portStr = props.getProperty(PropertyNames.PORT);
165
166 return initialize(portStr,props);
167 }
168
169 /**
170 * Initializes and starts the SNMP Adaptor Server.
171 **/
172 public static synchronized
173 AdaptorBootstrap initialize(String portStr, Properties props) {
174
175 // Get port number
176 if (portStr.length()==0) portStr=DefaultValues.PORT;
177 final int port;
178 try {
179 port = Integer.parseInt(portStr);
180 } catch (NumberFormatException x) {
181 throw new AgentConfigurationError(INVALID_SNMP_PORT, x, portStr);
182 }
183
184 if (port < 0) {
185 throw new AgentConfigurationError(INVALID_SNMP_PORT, portStr);
186 }
187
188 // Get trap port number
189 final String trapPortStr =
190 props.getProperty(PropertyNames.TRAP_PORT,
191 DefaultValues.TRAP_PORT);
192
193 final int trapPort;
194 try {
195 trapPort = Integer.parseInt(trapPortStr);
196 } catch (NumberFormatException x) {
197 throw new AgentConfigurationError(INVALID_SNMP_TRAP_PORT, x, trapPortStr);
198 }
199
200 if (trapPort < 0) {
201 throw new AgentConfigurationError(INVALID_SNMP_TRAP_PORT, trapPortStr);
202 }
203
204 // Get bind address
205 final String addrStr =
206 props.getProperty(PropertyNames.BIND_ADDRESS,
207 DefaultValues.BIND_ADDRESS);
208
209 // Get ACL File
210 final String defaultAclFileName =
211 getDefaultFileName(DefaultValues.ACL_FILE_NAME);
212 final String aclFileName =
213 props.getProperty(PropertyNames.ACL_FILE_NAME,
214 defaultAclFileName);
215 final String useAclStr =
216 props.getProperty(PropertyNames.USE_ACL,DefaultValues.USE_ACL);
217 final boolean useAcl =
218 Boolean.valueOf(useAclStr).booleanValue();
219
220 if (useAcl) checkAclFile(aclFileName);
221
222 AdaptorBootstrap adaptor = null;
223 try {
224 adaptor = getAdaptorBootstrap(port, trapPort, addrStr,
225 useAcl, aclFileName);
226 } catch (Exception e) {
227 throw new AgentConfigurationError(AGENT_EXCEPTION, e, e.getMessage());
228 }
229 return adaptor;
230 }
231
232 private static AdaptorBootstrap getAdaptorBootstrap
233 (int port, int trapPort, String bindAddress, boolean useAcl,
234 String aclFileName) {
235
236 final InetAddress address;
237 try {
238 address = InetAddress.getByName(bindAddress);
239 } catch (UnknownHostException e) {
240 throw new AgentConfigurationError(UNKNOWN_SNMP_INTERFACE, e, bindAddress);
241 }
242 if (log.isDebugOn()) {
243 log.debug("initialize",
244 Agent.getText("jmxremote.AdaptorBootstrap.getTargetList.starting" +
245 "\n\t" + PropertyNames.PORT + "=" + port +
246 "\n\t" + PropertyNames.TRAP_PORT + "=" + trapPort +
247 "\n\t" + PropertyNames.BIND_ADDRESS + "=" + address +
248 (useAcl?("\n\t" + PropertyNames.ACL_FILE_NAME + "="
249 + aclFileName):"\n\tNo ACL")+
250 ""));
251 }
252
253 final InetAddressAcl acl;
254 try {
255 acl = useAcl ? new SnmpAcl(System.getProperty("user.name"),aclFileName)
256 : null;
257 } catch (UnknownHostException e) {
258 throw new AgentConfigurationError(UNKNOWN_SNMP_INTERFACE, e, e.getMessage());
259 }
260
261 // Create adaptor
262 final SnmpAdaptorServer adaptor =
263 new SnmpAdaptorServer(acl, port, address);
264 adaptor.setUserDataFactory(new JvmContextFactory());
265 adaptor.setTrapPort(trapPort);
266
267 // Create MIB
268 //
269 final JVM_MANAGEMENT_MIB_IMPL mib = new JVM_MANAGEMENT_MIB_IMPL();
270 try {
271 mib.init();
272 } catch (IllegalAccessException x) {
273 throw new AgentConfigurationError(SNMP_MIB_INIT_FAILED, x, x.getMessage());
274 }
275
276 // Configure the trap destinations.
277 //
278 mib.addTargets(getTargetList(acl,trapPort));
279
280
281 // Start Adaptor
282 //
283 try {
284 // Will wait until the adaptor starts or fails to start.
285 // If the adaptor fails to start, a CommunicationException or
286 // an InterruptedException is thrown.
287 //
288 adaptor.start(Long.MAX_VALUE);
289 } catch (Exception x) {
290 Throwable t=x;
291 if (x instanceof com.sun.jmx.snmp.daemon.CommunicationException) {
292 final Throwable next = t.getCause();
293 if (next != null) t = next;
294 }
295 throw new AgentConfigurationError(SNMP_ADAPTOR_START_FAILED, t,
296 address + ":" + port,
297 "(" + t.getMessage() + ")");
298 }
299
300 // double check that adaptor is actually started (should always
301 // be active, so that exception should never be thrown from here)
302 //
303 if (!adaptor.isActive()) {
304 throw new AgentConfigurationError(SNMP_ADAPTOR_START_FAILED,
305 address + ":" + port);
306 }
307
308 try {
309 // Add MIB to adaptor
310 //
311 adaptor.addMib(mib);
312
313 // Add Adaptor to the MIB
314 //
315 mib.setSnmpAdaptor(adaptor);
316 } catch (RuntimeException x) {
317 new AdaptorBootstrap(adaptor,mib).terminate();
318 throw x;
319 }
320
321 log.debug("initialize",
322 Agent.getText("jmxremote.AdaptorBootstrap.getTargetList.initialize1"));
323 log.config("initialize",
324 Agent.getText("jmxremote.AdaptorBootstrap.getTargetList.initialize2",
325 address.toString(), java.lang.Integer.toString(adaptor.getPort())));
326 return new AdaptorBootstrap(adaptor,mib);
327 }
328
329 private static void checkAclFile(String aclFileName) {
330 if (aclFileName == null || aclFileName.length()==0) {
331 throw new AgentConfigurationError(SNMP_ACL_FILE_NOT_SET);
332 }
333 final File file = new File(aclFileName);
334 if (!file.exists()) {
335 throw new AgentConfigurationError(SNMP_ACL_FILE_NOT_FOUND, aclFileName);
336 }
337 if (!file.canRead()) {
338 throw new AgentConfigurationError(SNMP_ACL_FILE_NOT_READABLE, aclFileName);
339 }
340
341 FileSystem fs = FileSystem.open();
342 try {
343 if (fs.supportsFileSecurity(file)) {
344 if (!fs.isAccessUserOnly(file)) {
345 throw new AgentConfigurationError(SNMP_ACL_FILE_ACCESS_NOT_RESTRICTED,
346 aclFileName);
347 }
348 }
349 } catch (IOException e) {
350 throw new AgentConfigurationError(SNMP_ACL_FILE_READ_FAILED, aclFileName);
351
352 }
353 }
354
355
356 /**
357 * Get the port on which the adaptor is bound.
358 * Returns 0 if the adaptor is already terminated.
359 *
360 **/
361 public synchronized int getPort() {
362 if (adaptor != null) return adaptor.getPort();
363 return 0;
364 }
365
366 /**
367 * Stops the adaptor server.
368 **/
369 public synchronized void terminate() {
370 if (adaptor == null) return;
371
372 // Terminate the MIB (deregister NotificationListener from
373 // MemoryMBean)
374 //
375 try {
376 jvmmib.terminate();
377 } catch (Exception x) {
378 // Must not prevent to stop...
379 //
380 log.debug("jmxremote.AdaptorBootstrap.getTargetList.terminate",
381 x.toString());
382 } finally {
383 jvmmib=null;
384 }
385
386 // Stop the adaptor
387 //
388 try {
389 adaptor.stop();
390 } finally {
391 adaptor = null;
392 }
393 }
394
395}