Skip to main content
aboutsummaryrefslogtreecommitdiffstats
blob: 46c60a85e439c05dede4cd89a231a5f77ab7b532 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
/*******************************************************************************
 * Copyright (c) 2009 IBM Corporation and others.
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 * 
 * Contributors:
 *     IBM Corporation - initial API and implementation
 *     
 *******************************************************************************/
package org.eclipse.wst.sse.core.internal.util;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Hashtable;
import java.util.List;

import org.eclipse.core.runtime.Assert;
import org.eclipse.core.runtime.Platform;
import org.eclipse.wst.sse.core.internal.Logger;
import org.eclipse.wst.sse.core.internal.SSECorePlugin;
import org.osgi.framework.Bundle;
import org.osgi.framework.BundleContext;
import org.osgi.framework.BundleException;
import org.osgi.framework.ServiceRegistration;
import org.osgi.service.event.Event;
import org.osgi.service.event.EventAdmin;
import org.osgi.service.event.EventConstants;
import org.osgi.service.event.EventHandler;

/**
 * This responds to memory events.
 * 
 * Create an instance of a child of this class with the events you are interested in.
 * Then call connect() to start listening. To stop listening call disconnect();
 */
public abstract class AbstractMemoryListener implements EventHandler {
	/**
	 * The event that indicates that memory is running low at the lowest severity.
	 * Listeners are requested to release caches that can easily be recomputed.
	 * The Java VM is not seriously in trouble, but process size is getting higher than 
	 * is deemed acceptable.
	 */
	public static final String SEV_NORMAL = "org/eclipse/equinox/events/MemoryEvent/NORMAL"; //$NON-NLS-1$
	
	/**
	 * The event that indicates that memory is running low at medium severity. 
	 * Listeners are requested to release intermediate build results, complex models, etc.
	 * Memory is getting low and may cause operating system level stress, such as swapping.
	 */
	public static final String SEV_SERIOUS = "org/eclipse/equinox/events/MemoryEvent/SERIOUS"; //$NON-NLS-1$
	
	/**
	 * The event that indicates that memory is running low at highest severity.
	 * Listeners are requested to do things like close editors and perspectives, close database connections, etc.
	 * Restoring these resources and caches constitutes lots of work, but memory is so low that
	 * drastic measures are required.
	 */
	public static final String SEV_CRITICAL = "org/eclipse/equinox/events/MemoryEvent/CRITICAL"; //$NON-NLS-1$
	
	/**
	 * All of the valid memory severities
	 */
	public static final String[] SEV_ALL = { SEV_NORMAL, SEV_SERIOUS, SEV_CRITICAL };

	/**
	 * Used to register the {@link EventAdmin} listener
	 */
	private static BundleContext CONTEXT =
		(SSECorePlugin.getDefault() != null) ?
				SSECorePlugin.getDefault().getBundle().getBundleContext() : null;

	/**
	 * the severities that will be reacted to
	 */
	private final List fSeverities;
	
	/**
	 * service used to register this listener
	 */
	private ServiceRegistration fRegisterService;

	/**
	 * Will listen to all memory events
	 */
	public AbstractMemoryListener() {
		this(AbstractMemoryListener.SEV_ALL);
	}

	/**
	 * Will listen to memory events of the given <code>severity</code>
	 * 
	 * @param severity listen for memory events of this severity
	 */
	public AbstractMemoryListener(String severity) {
		Assert.isNotNull(severity, "Severity can not be null"); //$NON-NLS-1$
		
		List severities = new ArrayList(1);
		severities.add(severity);
		fSeverities = severities;
	}
	
	/**
	 * Will listen to memory events of the given <code>severities</code>
	 * 
	 * @param severities listen for memory events for any of these severities
	 */
	public AbstractMemoryListener(String[] severities) {
		Assert.isNotNull(severities, "Severities can not be null"); //$NON-NLS-1$
		Assert.isLegal(severities.length > 0, "Severities must specify at least one severity"); //$NON-NLS-1$
		
		fSeverities = Arrays.asList(severities);
	}

	/**
	 * Will listen to memory events of the given <code>severities</code>
	 * 
	 * @param severities listen for memory events for any of these severities
	 */
	public AbstractMemoryListener(List severities) {
		Assert.isNotNull(severities, "Severities can not be null"); //$NON-NLS-1$
		Assert.isLegal(!severities.isEmpty(), "Severities must specify at least one severity"); //$NON-NLS-1$
		fSeverities = severities;
	}

	/**
	 * Connect this listener to the {@link EventAdmin}
	 */
	public final void connect() {
		if (CONTEXT != null) {
			// NOTE: This is TEMPORARY CODE needed to load the plugin
			// until its done automatically by the product
			// TODO: Remove me
			Bundle b = Platform.getBundle("org.eclipse.equinox.event"); //$NON-NLS-1$
			if (b != null && b.getState() == Bundle.RESOLVED) {
				try {
					b.start(Bundle.START_TRANSIENT);
				}
				catch (BundleException e) {
					e.printStackTrace();
				}
			}
			// end remove me
			
			//register this handler
			String[] severities = (String[])fSeverities.toArray(new String[fSeverities.size()]);
			Hashtable prop = new Hashtable(1);
			prop.put(EventConstants.EVENT_TOPIC, severities);
			fRegisterService = CONTEXT.registerService(EventHandler.class.getName(), this, prop);
			
			//call any implementer specific connect code
			doConnect();
		} else {
			Logger.log(Logger.WARNING, "Error accessing bundle context. Is Platform running? Not tracking memory events. "); //$NON-NLS-1$
		}
	}

	/**
	 * Disconnect this listener to the {@link EventAdmin}
	 */
	public final void disconnect() {
		if (fRegisterService != null) {
			fRegisterService.unregister();
			fRegisterService = null;
		}
		
		//call any implementer specific disconnect code
		doDisconnect();
	}

	/**
	 * <p>Filter out any events that are not of the type that this listener handles</p>
	 * 
	 * @see org.osgi.service.event.EventHandler#handleEvent(org.osgi.service.event.Event)
	 */
	public final void handleEvent(Event event) {
		if (fSeverities.contains(event.getTopic())) {
			handleMemoryEvent(event);
		}
	}

	/**
	 * Implementing child classes may assume that only {@link Event}s of the types
	 * given to the constructor will be given to this method.
	 * 
	 * @param event the {@link Event} with a topic equal to one of the memory
	 * severities that this listener is listening for
	 */
	protected abstract void handleMemoryEvent(Event event);
	
	/**
	 * Implementers may overrun this method to do setup after connection of this listener
	 */
	protected void doConnect() {
		//do nothing by default
	}
	
	/**
	 * Implementers may overrun this method to do tear down after disconnection of this listener
	 */
	protected void doDisconnect() {
		//do nothing by default
	}
}

Back to the top