/*
* 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 com.sun.jini.phoenix;
import java.rmi.Remote;
import java.rmi.RemoteException;
import java.rmi.activation.ActivationDesc;
import java.rmi.activation.ActivationException;
import java.rmi.activation.ActivationGroupDesc;
import java.rmi.activation.ActivationGroupID;
import java.rmi.activation.ActivationID;
import java.rmi.activation.ActivationInstantiator;
import java.rmi.activation.ActivationMonitor;
import java.rmi.activation.ActivationSystem;
import java.rmi.activation.UnknownGroupException;
import java.rmi.server.ExportException;
import java.util.Map;
import net.jini.export.Exporter;
import net.jini.jrmp.JrmpExporter;
/**
* Exporter that wraps an <code>ActivationSystem</code> instance so that it
* only accepts calls from the local host and optionally enforces a
* {@link GroupPolicy} on calls to <code>registerGroup</code> and
* <code>setActivationGroupDesc</code>.
*
* @author Sun Microsystems, Inc.
*
* @since 2.0
*/
public class SystemAccessExporter implements Exporter {
/**
* The underlying exporter.
*/
private final Exporter exporter;
/**
* The group policy, if any.
*/
private final GroupPolicy policy;
/**
* The wrapped impl.
*/
private Remote wrapped;
/**
* Creates an exporter with an underlying {@link SunJrmpExporter} that
* exports using a well-known object identifier (4) on the standard
* activation port (1098), and a {@link DefaultGroupPolicy} instance.
*/
public SystemAccessExporter() {
this(ActivationSystem.SYSTEM_PORT);
}
/**
* Creates an exporter with an underlying {@link SunJrmpExporter} that
* exports using a well-known object identifier (4) on the standard
* activation port (1098), and the specified group policy, if any.
*
* @param policy the group policy, or <code>null</code>
*/
public SystemAccessExporter(GroupPolicy policy) {
this(ActivationSystem.SYSTEM_PORT, policy);
}
/**
* Creates an exporter with an underlying {@link SunJrmpExporter} that
* exports using a well-known object identifier (4) on the specified port,
* and a {@link DefaultGroupPolicy} instance.
*
* @param port the port on which to receive calls (if zero, an anonymous
* port will be chosen)
*/
public SystemAccessExporter(int port) {
this(port, new DefaultGroupPolicy());
}
/**
* Creates an exporter with an underlying {@link SunJrmpExporter} that
* exports using a well-known object identifier (4) on the specified port,
* and the specified group policy, if any.
*
* @param port the port on which to receive calls (if zero, an anonymous
* port will be chosen)
* @param policy the group policy, or <code>null</code>
*/
public SystemAccessExporter(int port, GroupPolicy policy) {
this(new SunJrmpExporter(4, port), policy);
}
/**
* Creates an exporter with the specified underlying exporter and a
* {@link DefaultGroupPolicy} instance.
*
* @param exporter the underlying exporter
*/
public SystemAccessExporter(Exporter exporter) {
this(exporter, new DefaultGroupPolicy());
}
/**
* Creates an exporter with the specified underlying exporter and the
* specified group policy, if any.
*
* @param exporter the underlying exporter
* @param policy the group policy, or <code>null</code>
*/
public SystemAccessExporter(Exporter exporter, GroupPolicy policy) {
this.exporter = exporter;
this.policy = policy;
}
/**
* Wraps the specified remote object in an <code>ActivationSystem</code>
* implementation that only accepts calls from the local host and
* enforces the group policy (if any) before delegating to the specified
* remote object, exports the wrapper with the underlying exporter, and
* returns the resulting proxy. The wrapper is strongly referenced by
* this exporter. For all <code>ActivationSystem</code> and
* <code>ActivationAdmin</code> methods, the wrapper throws an
* <code>AccessControlException</code> if the client is not calling from
* the local host. For the <code>registerGroup</code> and
* <code>setActivationGroupDesc</code> methods, the policy (if any)
* is checked by calling its {@link GroupPolicy#checkGroup checkGroup}
* method with the <code>ActivationGroupDesc</code> argument.
*
* @throws IllegalArgumentException if <code>impl</code> does not
* implement <code>ActivationSystem</code> or <code>ActivationAdmin</code>
* @throws NullPointerException {@inheritDoc}
* @throws IllegalStateException {@inheritDoc}
*/
public Remote export(Remote impl) throws ExportException {
if (!(impl instanceof ActivationSystem)) {
throw new IllegalArgumentException("not an ActivationSystem");
}
if (!(impl instanceof ActivationAdmin)) {
throw new IllegalArgumentException("not an ActivationAdmin");
}
Remote wrapped = new SystemImpl((ActivationSystem) impl, policy);
Remote proxy = exporter.export(wrapped);
this.wrapped = wrapped;
return proxy;
}
/**
* @throws IllegalStateException {@inheritDoc}
*/
public boolean unexport(boolean force) {
return exporter.unexport(force);
}
private static class SystemImpl extends AbstractSystem {
private final ActivationSystem impl;
private final GroupPolicy policy;
SystemImpl(ActivationSystem impl, GroupPolicy policy) {
this.impl = impl;
this.policy = policy;
}
public ActivationID registerObject(ActivationDesc desc)
throws ActivationException, RemoteException
{
LocalAccess.check();
return impl.registerObject(desc);
}
public void unregisterObject(ActivationID id)
throws ActivationException, RemoteException
{
LocalAccess.check();
impl.unregisterObject(id);
}
public ActivationGroupID registerGroup(ActivationGroupDesc desc)
throws ActivationException, RemoteException
{
LocalAccess.check();
if (policy != null) {
policy.checkGroup(desc);
}
return impl.registerGroup(desc);
}
public ActivationMonitor activeGroup(ActivationGroupID id,
ActivationInstantiator group,
long incarnation)
throws ActivationException, RemoteException
{
LocalAccess.check();
return impl.activeGroup(id, group, incarnation);
}
public void unregisterGroup(ActivationGroupID id)
throws ActivationException, RemoteException
{
LocalAccess.check();
impl.unregisterGroup(id);
}
public ActivationDesc setActivationDesc(ActivationID id,
ActivationDesc desc)
throws ActivationException, RemoteException
{
LocalAccess.check();
return impl.setActivationDesc(id, desc);
}
public ActivationGroupDesc setActivationGroupDesc(
ActivationGroupID id,
ActivationGroupDesc desc)
throws ActivationException, RemoteException
{
LocalAccess.check();
if (policy != null) {
policy.checkGroup(desc);
}
return impl.setActivationGroupDesc(id, desc);
}
public ActivationDesc getActivationDesc(ActivationID id)
throws ActivationException, RemoteException
{
LocalAccess.check();
return impl.getActivationDesc(id);
}
public ActivationGroupDesc getActivationGroupDesc(ActivationGroupID id)
throws ActivationException, RemoteException
{
LocalAccess.check();
return impl.getActivationGroupDesc(id);
}
public void shutdown() throws RemoteException {
LocalAccess.check();
impl.shutdown();
}
public Map getActivationGroups() throws RemoteException {
LocalAccess.check();
return ((ActivationAdmin) impl).getActivationGroups();
}
public Map getActivatableObjects(ActivationGroupID id)
throws UnknownGroupException, RemoteException
{
LocalAccess.check();
return ((ActivationAdmin) impl).getActivatableObjects(id);
}
}
}