| /* |
| * 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.apache.felix.webconsole.plugins.event.internal; |
| |
| |
| import java.io.ByteArrayOutputStream; |
| import java.io.IOException; |
| import java.io.InputStream; |
| import java.io.PrintWriter; |
| import java.net.URL; |
| import java.util.Date; |
| import java.util.Dictionary; |
| import java.util.Iterator; |
| import java.util.List; |
| import java.util.Map; |
| |
| import javax.servlet.ServletException; |
| import javax.servlet.http.HttpServlet; |
| import javax.servlet.http.HttpServletRequest; |
| import javax.servlet.http.HttpServletResponse; |
| |
| import org.apache.felix.utils.json.JSONWriter; |
| import org.osgi.service.event.Event; |
| import org.osgi.service.event.EventAdmin; |
| |
| /** |
| * The Event Plugin |
| */ |
| public class PluginServlet extends HttpServlet |
| { |
| |
| private static final long serialVersionUID = -8601361741848077124L; |
| |
| private static final String ACTION_POST = "post"; //$NON-NLS-1$ |
| private static final String ACTION_SEND = "send"; //$NON-NLS-1$ |
| private static final String ACTION_CLEAR = "clear"; //$NON-NLS-1$ |
| |
| private static final String PARAMETER_ACTION = "action"; //$NON-NLS-1$ |
| |
| /** The event collector. */ |
| private final EventCollector collector; |
| |
| /** Is the config admin available? */ |
| private volatile boolean configAdminAvailable = false; |
| |
| private EventAdmin eventAdmin; |
| |
| private final String TEMPLATE; |
| |
| public PluginServlet() |
| { |
| this.collector = new EventCollector(); |
| TEMPLATE = readTemplateFile(getClass(), "/res/events.html"); //$NON-NLS-1$ |
| } |
| |
| private final String readTemplateFile(final Class<?> clazz, final String templateFile) |
| { |
| InputStream templateStream = getClass().getResourceAsStream(templateFile); |
| if (templateStream != null) |
| { |
| ByteArrayOutputStream baos = new ByteArrayOutputStream(); |
| byte[] data = new byte[1024]; |
| try |
| { |
| int len = 0; |
| while ((len = templateStream.read(data)) > 0) |
| { |
| baos.write(data, 0, len); |
| } |
| return baos.toString("UTF-8"); //$NON-NLS-1$ |
| } |
| catch (IOException e) |
| { |
| // don't use new Exception(message, cause) because cause is 1.4+ |
| throw new RuntimeException("readTemplateFile: Error loading " |
| + templateFile + ": " + e); |
| } |
| finally |
| { |
| try |
| { |
| templateStream.close(); |
| } |
| catch (IOException e) |
| { |
| /* ignore */ |
| } |
| |
| } |
| } |
| |
| // template file does not exist, return an empty string |
| log("readTemplateFile: File '" + templateFile + "' not found through class " |
| + clazz); |
| return ""; //$NON-NLS-1$ |
| } |
| |
| private static final Event newEvent(HttpServletRequest request) |
| { |
| String topic = request.getParameter("topic"); //$NON-NLS-1$ |
| |
| return new Event(topic, PropertiesEditorSupport.convertProperties(request)); |
| } |
| |
| |
| /** |
| * @see javax.servlet.http.HttpServlet#doPost(javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse) |
| */ |
| @Override |
| protected void doPost( HttpServletRequest req, HttpServletResponse resp ) |
| throws ServletException, IOException |
| { |
| final String action = req.getParameter( PARAMETER_ACTION ); |
| if ( ACTION_POST.equals(action) ) { |
| final Event event = newEvent(req); |
| eventAdmin.postEvent(event); |
| } else if (ACTION_SEND.equals(action)) { |
| final Event event = newEvent(req); |
| eventAdmin.sendEvent(event); |
| } else if ( ACTION_CLEAR.equals( action ) ) { |
| this.collector.clear(); |
| } |
| // we always send back the json data |
| resp.setContentType( "application/json" ); //$NON-NLS-1$ |
| resp.setCharacterEncoding( "utf-8" ); //$NON-NLS-1$ |
| |
| renderJSON( resp.getWriter() ); |
| } |
| |
| private void renderJSON( final PrintWriter pw ) throws IOException |
| { |
| List<EventInfo> events = this.collector.getEvents(); |
| |
| StringBuffer statusLine = new StringBuffer(); |
| statusLine.append( events.size() ); |
| statusLine.append( " Event"); |
| if ( events.size() != 1 ) |
| { |
| statusLine.append('s'); |
| } |
| statusLine.append( " received" ); |
| if ( !events.isEmpty() ) |
| { |
| statusLine.append( " since " ); |
| Date d = new Date(); |
| d.setTime( events.get( 0 ).received ); |
| statusLine.append( d ); |
| } |
| statusLine.append( ". (Event admin: " ); |
| if ( this.eventAdmin == null ) |
| { |
| statusLine.append("un"); |
| } |
| statusLine.append("available; Config admin: "); |
| if ( !this.configAdminAvailable ) |
| { |
| statusLine.append("un"); |
| } |
| statusLine.append("available)"); |
| |
| // Compute scale: startTime is 0, lastTimestamp is 100% |
| final long startTime = this.collector.getStartTime(); |
| final long endTime = (events.size() == 0 ? startTime : events.get(events.size() - 1).received); |
| final float scale = (endTime == startTime ? 100.0f : 100.0f / (endTime - startTime)); |
| |
| final JSONWriter writer = new JSONWriter(pw); |
| writer.object(); |
| writer.key( "status" ); |
| writer.value( statusLine.toString() ); |
| |
| writer.key( "data" ); |
| writer.array(); |
| |
| // display list in reverse order |
| for ( int index = events.size() - 1; index >= 0; index-- ) |
| { |
| eventJson( writer, events.get( index ), index, startTime, scale ); |
| } |
| |
| writer.endArray(); |
| |
| writer.endObject(); |
| } |
| |
| |
| @Override |
| protected void doGet( HttpServletRequest request, HttpServletResponse response ) |
| throws ServletException, IOException |
| { |
| |
| final String info = request.getPathInfo(); |
| if ( info.endsWith( ".json" ) ) //$NON-NLS-1$ |
| { |
| response.setContentType( "application/json" ); //$NON-NLS-1$ |
| response.setCharacterEncoding( "UTF-8" ); //$NON-NLS-1$ |
| |
| PrintWriter pw = response.getWriter(); |
| this.renderJSON( pw ); |
| |
| // nothing more to do |
| return; |
| } |
| |
| this.renderContent( request, response ); |
| } |
| |
| |
| protected void renderContent( HttpServletRequest request, HttpServletResponse response ) |
| throws ServletException, IOException |
| { |
| final PrintWriter pw = response.getWriter(); |
| //final String appRoot = ( String ) request.getAttribute( "felix.webconsole.appRoot" ); |
| //pw.println( "<script src='" + appRoot + "/events/res/ui/" + "events.js" + "' type='text/javascript'></script>" ); |
| pw.print(TEMPLATE); |
| } |
| |
| public URL getResource(String path) |
| { |
| if ( path.startsWith("/events/res/ui/") ) //$NON-NLS-1$ |
| { |
| return this.getClass().getResource(path.substring(7)); |
| } |
| return null; |
| } |
| |
| |
| private void eventJson( JSONWriter jw, EventInfo info, int index, final long start, final float scale ) |
| throws IOException |
| { |
| final long msec = info.received - start; |
| |
| // Compute color bar size and make sure the bar is visible |
| final int percent = Math.max((int)(msec * scale), 2); |
| |
| jw.object(); |
| jw.key( "id" ); |
| jw.value( String.valueOf( index ) ); |
| |
| jw.key( "offset" ); |
| jw.value( msec ); |
| |
| jw.key( "width" ); |
| jw.value( percent ); |
| |
| jw.key( "category" ); |
| jw.value( info.category ); |
| |
| jw.key( "received" ); |
| jw.value( info.received ); |
| |
| jw.key( "topic" ); |
| jw.value( info.topic ); |
| |
| if ( info.info != null ) |
| { |
| jw.key( "info" ); |
| jw.value( info.info ); |
| } |
| |
| jw.key( "properties" ); |
| jw.object(); |
| if ( info.properties != null && info.properties.size() > 0 ) |
| { |
| final Iterator<Map.Entry<String, Object>> i = info.properties.entrySet().iterator(); |
| while ( i.hasNext() ) |
| { |
| final Map.Entry<String, Object> current = i.next(); |
| jw.key( current.getKey().toString() ); |
| jw.value(current.getValue()); |
| } |
| } |
| jw.endObject(); |
| |
| jw.endObject(); |
| } |
| |
| public void updateConfiguration( Dictionary<String, ?> dict) |
| { |
| this.collector.updateConfiguration(dict); |
| } |
| |
| public EventCollector getCollector() |
| { |
| return this.collector; |
| } |
| |
| public void setEventAdmin(final EventAdmin eventAdmin) |
| { |
| this.eventAdmin = eventAdmin; |
| } |
| |
| public void setConfigAdminAvailable(final boolean flag) |
| { |
| this.configAdminAvailable = flag; |
| } |
| } |