/*
* Copyright 2008 the original author or authors.
*
* Licensed 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.rioproject.monitor.service.channel;
import org.rioproject.associations.AssociationDescriptor;
import org.rioproject.opstring.ClassBundle;
import org.rioproject.opstring.ServiceElement;
import org.rioproject.impl.servicebean.ServiceElementUtil;
import java.util.*;
/**
* The ServiceChannel provides a local notification channel for service instances that have
* been provisioned, failed or gone idle.
*
* @author Dennis Reedy
*/
public final class ServiceChannel {
private final List<Registration> registrations = new ArrayList<Registration>();
private static final ServiceChannel instance = new ServiceChannel();
public static ServiceChannel getInstance() {
return instance;
}
public void subscribe(final ServiceChannelListener listener,
final AssociationDescriptor associationDescriptor,
final ServiceChannelEvent.Type type) {
subscribe(listener,
associationDescriptor.getName(),
associationDescriptor.getInterfaceNames(),
associationDescriptor.getOperationalStringName(),
type);
}
public void subscribe(final ServiceChannelListener listener,
final ServiceElement serviceElement,
final ServiceChannelEvent.Type type) {
ClassBundle[] exports = serviceElement.getExportBundles();
String[] interfaceNames = new String[exports.length];
for(int i=0; i< interfaceNames.length; i++) {
interfaceNames[i] = exports[i].getClassName();
}
subscribe(listener,
serviceElement.getName(),
interfaceNames,
serviceElement.getOperationalStringName(),
type);
}
private void subscribe(final ServiceChannelListener listener,
final String name,
final String[] interfaces,
final String opStringName,
final ServiceChannelEvent.Type type) {
Registration reg = new Registration(listener, name, interfaces, opStringName, type);
if(!registrations.contains(reg)) {
registrations.add(reg);
}
}
public void unsubscribe(final ServiceChannelListener listener) {
Registration[] regs = getRegistrations();
for (Registration r : regs) {
if (r.getServiceChannelListener().equals(listener)) {
registrations.remove(r);
}
}
}
public void broadcast(final ServiceChannelEvent event) {
Object[] arrLocal = getRegistrations();
for (Object anArrLocal : arrLocal) {
Registration r = (Registration) anArrLocal;
if (r.matches(event.getServiceElement(), event.getType())) {
r.getServiceChannelListener().notify(event);
}
}
}
private Registration[] getRegistrations() {
Registration[] regs;
synchronized(this) {
regs = registrations.toArray(new Registration[registrations.size()]);
}
return(regs);
}
private class Registration {
final ServiceChannelListener listener;
final String name;
final String[] interfaces;
final String opStringName;
final ServiceChannelEvent.Type type;
Registration(final ServiceChannelListener listener,
final String name,
final String[] interfaces,
final String opStringName,
final ServiceChannelEvent.Type type) {
this.listener = listener;
this.name = name;
this.interfaces = interfaces;
this.opStringName = opStringName;
this.type = type;
}
boolean matches(final ServiceElement element, final ServiceChannelEvent.Type type) {
return(ServiceElementUtil.matchesServiceElement(element, name, interfaces, opStringName) &&
this.type.equals(type));
}
ServiceChannelListener getServiceChannelListener() {
return(listener);
}
@Override
public boolean equals(Object o) {
if (this == o)
return true;
if(!(o instanceof Registration)) {
return (false);
}
Registration that = (Registration) o;
return Arrays.equals(interfaces, that.interfaces) &&
listener.equals(that.listener) &&
name.equals(that.name) &&
opStringName.equals(that.opStringName) &&
type == that.type;
}
@Override
public int hashCode() {
int result = listener.hashCode();
result = 31 * result + name.hashCode();
result = 31 * result + Arrays.hashCode(interfaces);
result = 31 * result + opStringName.hashCode();
result = 31 * result + type.hashCode();
return result;
}
}
}