| /* |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you under the Apache License, Version 2.0 (the |
| * "License"); you may not use this file except in compliance |
| * with the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, |
| * software distributed under the License is distributed on an |
| * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| * KIND, either express or implied. See the License for the |
| * specific language governing permissions and limitations |
| * under the License. |
| */ |
| |
| package org.netbeans.modules.weblogic.common; |
| |
| import java.io.IOException; |
| import java.util.HashMap; |
| import java.util.Map; |
| import java.util.concurrent.Callable; |
| import java.util.logging.Level; |
| import java.util.logging.Logger; |
| import javax.management.AttributeNotFoundException; |
| import javax.management.InstanceNotFoundException; |
| import javax.management.MBeanException; |
| import javax.management.MBeanServerConnection; |
| import javax.management.MalformedObjectNameException; |
| import javax.management.ObjectName; |
| import javax.management.ReflectionException; |
| import javax.management.remote.JMXConnector; |
| import javax.management.remote.JMXConnectorFactory; |
| import javax.management.remote.JMXServiceURL; |
| import org.netbeans.api.extexecution.base.input.InputProcessor; |
| import org.netbeans.api.extexecution.base.input.InputReader; |
| import org.netbeans.modules.weblogic.common.api.WebLogicConfiguration; |
| import org.openide.util.RequestProcessor; |
| |
| /** |
| * |
| * @author Petr Hejl |
| */ |
| public class RemoteLogInputReader implements InputReader { |
| |
| private static final Logger LOGGER = Logger.getLogger(RemoteLogInputReader.class.getName()); |
| |
| private static final int INITIAL_LOG_COUNT = 300; |
| |
| private static final int POLL_INTERVAL = 2000; |
| |
| private final WebLogicConfiguration config; |
| |
| private final Callable<String> nonProxy; |
| |
| // GuardeBy("this") |
| private final StringBuilder builder = new StringBuilder(); |
| |
| // GuardeBy("this") |
| private RequestProcessor worker; |
| |
| private volatile boolean closed; |
| |
| public RemoteLogInputReader(WebLogicConfiguration config, Callable<String> nonProxy) { |
| this.config = config; |
| this.nonProxy = nonProxy; |
| } |
| |
| @Override |
| public int readInput(InputProcessor processor) throws IOException { |
| if (closed) { |
| throw new IllegalStateException("Already closed reader"); |
| } |
| |
| synchronized (this) { |
| if (worker == null) { |
| worker = new RequestProcessor(RemoteLogInputReader.class); |
| worker.post(new Worker()); |
| } else { |
| int length = builder.length(); |
| if (length > 0) { |
| if (processor != null) { |
| processor.processInput(builder.toString().toCharArray()); |
| } |
| builder.setLength(0); |
| return length; |
| } |
| } |
| } |
| return 0; |
| } |
| |
| @Override |
| public void close() throws IOException { |
| closed = true; |
| } |
| |
| private class Worker implements Runnable { |
| |
| private JMXConnector connector; |
| |
| private boolean configured; |
| |
| private int recordIdIndex; |
| |
| private int timestampIndex; |
| |
| private int severityIndex; |
| |
| private int subsystemIndex; |
| |
| private int messageIdIndex; |
| |
| private int messageIndex; |
| |
| private Long recordId; |
| |
| @Override |
| public void run() { |
| boolean interrupted = false; |
| try { |
| while (true) { |
| if (Thread.currentThread().isInterrupted() || RemoteLogInputReader.this.closed) { |
| interrupted = Thread.interrupted(); |
| break; |
| } |
| |
| JMXConnector current = getConnector(); |
| if (current != null) { |
| try { |
| MBeanServerConnection con = current.getMBeanServerConnection(); |
| ObjectName service = new ObjectName("com.bea:Name=DomainRuntimeService," // NOI18N |
| + "Type=weblogic.management.mbeanservers.domainruntime.DomainRuntimeServiceMBean"); // NOI18N |
| ObjectName[] adminServers = (ObjectName[]) con |
| .getAttribute(service, "ServerRuntimes"); // NOI18N |
| String serverName = null; |
| for (ObjectName adminServer : adminServers) { |
| if ((Boolean) con.getAttribute(adminServer, "AdminServer")) { // NOI18N |
| serverName = con.getAttribute(adminServer, "Name").toString(); // NOI18N |
| break; |
| } |
| } |
| if (serverName != null) { |
| ObjectName wldf = new ObjectName("com.bea:Name=DomainLog," // NOI18N |
| + "ServerRuntime=" + serverName + ",Location=" + serverName + ",Type=WLDFDataAccessRuntime,WLDFAccessRuntime=Accessor,WLDFRuntime=WLDFRuntime"); // NOI18N |
| setColumns(con, wldf); |
| Long lastRecordId = (Long) con.getAttribute(wldf, "LatestRecordId"); // NOI18N |
| |
| if (recordId == null || !recordId.equals(lastRecordId)) { |
| Long from = recordId == null ? lastRecordId - INITIAL_LOG_COUNT : recordId + 1; |
| if (from < 0) { |
| from = (long) 0; |
| } |
| Long to = lastRecordId + 1; |
| String cursorName = (String) con.invoke(wldf, "openCursor", // NOI18N |
| new Object[]{from, to, Long.MAX_VALUE, null}, |
| new String[]{"java.lang.Long", "java.lang.Long", "java.lang.Long", "java.lang.String"}); // NOI18N |
| try { |
| while ((Boolean) con.invoke(wldf, "hasMoreData", new Object[]{cursorName}, // NOI18N |
| new String[]{"java.lang.String"})) { // NOI18N |
| Object[] data = (Object[]) con.invoke(wldf, "fetch", // NOI18N |
| new Object[]{cursorName}, new String[]{"java.lang.String"}); // NOI18N |
| synchronized (RemoteLogInputReader.this) { |
| for (Object item : data) { |
| if (item instanceof Object[]) { |
| Object[] values = (Object[]) item; |
| Long id = (Long) values[recordIdIndex]; |
| if (recordId == null || id > recordId) { |
| recordId = id; |
| } |
| append(builder, values[timestampIndex]); |
| append(builder, values[severityIndex]); |
| append(builder, values[subsystemIndex]); |
| append(builder, values[messageIdIndex]); |
| append(builder, values[messageIndex]); |
| } else { |
| append(builder, item); |
| } |
| builder.append("\n"); // NOI18N |
| } |
| } |
| } |
| } finally { |
| con.invoke(wldf, "closeCursor", // NOI18N |
| new Object[]{cursorName}, new String[]{"java.lang.String"}); // NOI18N |
| } |
| } |
| } |
| } catch (IOException ex) { |
| LOGGER.log(Level.FINE, null, ex); |
| closeConnector(); |
| } catch (MalformedObjectNameException ex) { |
| LOGGER.log(Level.INFO, null, ex); |
| } catch (InstanceNotFoundException ex) { |
| LOGGER.log(Level.INFO, null, ex); |
| } catch (MBeanException ex) { |
| LOGGER.log(Level.INFO, null, ex); |
| } catch (ReflectionException ex) { |
| LOGGER.log(Level.INFO, null, ex); |
| } catch (AttributeNotFoundException ex) { |
| LOGGER.log(Level.INFO, null, ex); |
| } |
| } |
| try { |
| Thread.sleep(POLL_INTERVAL); |
| } catch (InterruptedException ex) { |
| LOGGER.log(Level.FINE, null, ex); |
| interrupted = true; |
| break; |
| } |
| } |
| } finally { |
| closeConnector(); |
| if (interrupted) { |
| Thread.currentThread().interrupt(); |
| } |
| } |
| } |
| |
| private JMXConnector getConnector() { |
| if (connector != null) { |
| return connector; |
| } |
| |
| try { |
| connector = config.getRemote().executeAction(new Callable<JMXConnector>() { |
| |
| @Override |
| public JMXConnector call() throws Exception { |
| JMXServiceURL url = new JMXServiceURL(config.isSecured() ? "t3s" : "t3", // NOI18N |
| config.getHost(), config.getPort(), "/jndi/weblogic.management.mbeanservers.domainruntime"); // NOI18N |
| |
| String username = config.getUsername(); |
| String password = config.getPassword(); |
| |
| Map<String, Object> env = new HashMap<String, Object>(); |
| env.put(JMXConnectorFactory.PROTOCOL_PROVIDER_PACKAGES, |
| "weblogic.management.remote"); // NOI18N |
| env.put(javax.naming.Context.SECURITY_PRINCIPAL, username); |
| env.put(javax.naming.Context.SECURITY_CREDENTIALS, password); |
| env.put("jmx.remote.credentials", // NOI18N |
| new String[]{username, password}); |
| env.put("jmx.remote.protocol.provider.class.loader", //NOI18N |
| config.getLayout().getClassLoader()); |
| |
| JMXConnector jmxConnector = JMXConnectorFactory.newJMXConnector(url, env); |
| jmxConnector.connect(); |
| |
| return jmxConnector; |
| } |
| }, nonProxy); |
| } catch (Exception ex) { |
| connector = null; |
| LOGGER.log(Level.INFO, null, ex); |
| } |
| return connector; |
| } |
| |
| private void closeConnector() { |
| if (connector != null) { |
| try { |
| connector.close(); |
| connector = null; |
| configured = false; |
| } catch (IOException ex1) { |
| LOGGER.log(Level.FINE, null, ex1); |
| } |
| } |
| } |
| |
| private void setColumns(MBeanServerConnection connection, ObjectName wldf) throws MBeanException, |
| AttributeNotFoundException, InstanceNotFoundException, ReflectionException, IOException { |
| |
| if (configured) { |
| return; |
| } |
| |
| Map columnIndexMap = (Map) connection.getAttribute(wldf, "ColumnIndexMap"); // NOI18N |
| recordIdIndex = ((Integer) columnIndexMap.get("RECORDID")); // NOI18N |
| timestampIndex = ((Integer) columnIndexMap.get("DATE")); // NOI18N |
| severityIndex = ((Integer) columnIndexMap.get("SEVERITY")); // NOI18N |
| subsystemIndex = ((Integer) columnIndexMap.get("SUBSYSTEM")); // NOI18N |
| messageIdIndex = ((Integer) columnIndexMap.get("MSGID")); // NOI18N |
| messageIndex = ((Integer) columnIndexMap.get("MESSAGE")); // NOI18N |
| configured = true; |
| } |
| |
| private void append(StringBuilder builder, Object value) { |
| builder.append("<"); // NOI18N |
| builder.append(value.toString()); |
| builder.append("> "); // NOI18N |
| } |
| } |
| } |