/*
* 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.lang.reflect.Method;
import java.rmi.Remote;
import java.rmi.activation.ActivationGroupDesc;
import java.rmi.activation.ActivationSystem;
import java.rmi.server.ExportException;
import java.util.Collection;
import net.jini.core.constraint.InvocationConstraints;
import net.jini.core.constraint.MethodConstraints;
import net.jini.jeri.BasicILFactory;
import net.jini.jeri.BasicInvocationDispatcher;
import net.jini.jeri.InvocationDispatcher;
import net.jini.jeri.ServerCapabilities;
/**
* Invocation layer factory for exporting an {@link ActivationSystem}
* to use Jini extensible remote invocation (Jini ERI), that is similar
* to {@link BasicILFactory} except the remote object must be an
* <code>ActivationSystem</code> instance and the returned dispatcher
* optionally accepts calls from the local host and optionally enforces a
* {@link GroupPolicy} on calls to {@link ActivationSystem#registerGroup
* registerGroup} and {@link ActivationSystem#setActivationGroupDesc
* setActivationGroupDesc}.
*
* @author Sun Microsystems, Inc.
*
* @since 2.0
* @see SystemAccessProxyTrustILFactory
**/
public class SystemAccessILFactory extends BasicILFactory {
/**
* The group policy, if any.
*/
private final GroupPolicy policy;
/**
* If true, check that client is calling from the local host.
*/
private final boolean localAccessCheck;
/**
* Creates an invocation layer factory that creates an invocation
* dispatcher with a {@link DefaultGroupPolicy} instance and a
* <code>null</code> class loader. This invocation dispatcher only
* accepts calls from the local host and enforces the group policy on
* calls to {@link ActivationSystem#registerGroup registerGroup} and
* {@link ActivationSystem#setActivationGroupDesc
* setActivationGroupDesc}.
**/
public SystemAccessILFactory() {
this(new DefaultGroupPolicy(), null);
}
/**
* Creates an invocation layer factory that creates an invocation
* dispatcher with the specified group policy and the specified class
* loader. This invocation dispatcher only accepts calls from the
* local host and enforces the specified group policy (if
* non-<code>null</code>) on calls to {@link
* ActivationSystem#registerGroup registerGroup} and {@link
* ActivationSystem#setActivationGroupDesc setActivationGroupDesc}.
*
* @param loader the class loader, or <code>null</code>
* @param policy the group policy, or <code>null</code>
**/
public SystemAccessILFactory(GroupPolicy policy, ClassLoader loader) {
super(null, null, loader);
this.policy = policy;
this.localAccessCheck = true;
}
/**
* Creates a factory with a <code>null</code> class loader, the
* specified server constraints, the {@link SystemPermission}
* permission class, and a {@link DefaultGroupPolicy} instance.
*
* @param serverConstraints the server constraints, or <code>null</code>
**/
public SystemAccessILFactory(MethodConstraints serverConstraints) {
this(serverConstraints, SystemPermission.class,
new DefaultGroupPolicy(), null);
}
/**
* Creates a factory with the specified server constraints, permission
* class, group policy, and class loader. This factory creates an
* invocation dispatcher that enforces the specified group policy (if
* non-<code>null</code>) on calls to {@link
* ActivationSystem#registerGroup registerGroup} and {@link
* ActivationSystem#setActivationGroupDesc setActivationGroupDesc}.
*
* @param serverConstraints the server constraints, or <code>null</code>
* @param permClass the permission class, or <code>null</code>
* @param policy the group policy, or <code>null</code>
* @param loader the class loader, or <code>null</code>
* @throws IllegalArgumentException if the permission class is abstract, is
* not a subclass of {@link java.security.Permission}, or does not have
* a public constructor that has either one <code>String</code> parameter
* or one {@link Method} parameter and has no declared exceptions
**/
public SystemAccessILFactory(MethodConstraints serverConstraints,
Class permClass,
GroupPolicy policy,
ClassLoader loader)
{
super(serverConstraints, permClass, loader);
this.policy = policy;
this.localAccessCheck = false;
}
/**
* Returns a {@link SystemDispatcher} instance constructed with the
* specified methods, the class loader specified during construction,
* the remote object, server capabilities, and the server constraints,
* permission class, and group policy that this factory was constructed
* with and a flag indicating whether the dispatcher should only accept
* calls from the local host.
*
* @return a {@link SystemDispatcher} instance constructed with the
* specified methods, remote object, and server capabilities, and the
* server constraints, permission class, group policy, local host access
* check condition, and class loader that this factory was constructed
* with
* @throws NullPointerException {@inheritDoc}
**/
protected InvocationDispatcher
createInvocationDispatcher(Collection methods,
Remote impl,
ServerCapabilities caps)
throws ExportException
{
if (impl == null) {
throw new NullPointerException("impl cannot be null");
} else if (!(impl instanceof ActivationSystem)) {
throw new ExportException("cannot create dispatcher",
new IllegalArgumentException(
"impl must be an ActivationSystem"));
}
return new SystemDispatcher(methods, impl, caps,
getServerConstraints(),
getPermissionClass(), policy,
localAccessCheck, getClassLoader());
}
/**
* A subclass of {@link BasicInvocationDispatcher} for
* <code>ActivationSystem</code> instances that optionally enforces a
* {@link GroupPolicy} on calls to <code>registerGroup</code> and
* <code>setActivationGroupDesc</code>.
*/
public static class SystemDispatcher extends BasicInvocationDispatcher {
/**
* The group policy, if any.
*/
private final GroupPolicy policy;
/**
* If true, check that client is calling from the local host.
*/
private final boolean localAccessCheck;
/**
* Creates an invocation dispatcher to receive incoming remote calls
* for the specified methods, for a server and transport with the
* specified capabilities, enforcing the specified constraints, and
* performing preinvocation access control using the specified
* permission class and group policy. The specified class loader
* is used by the {@link #createMarshalInputStream
* createMarshalInputStream} method.
*
* <p>For each combination of constraints that might need to be
* enforced (obtained by calling the {@link
* MethodConstraints#possibleConstraints possibleConstraints}
* method on the specified server constraints, or using an empty
* constraints instance of the specified server constraints
* instance is <code>null</code>), calling the {@link
* ServerCapabilities#checkConstraints checkConstraints}
* method of the specified capabilities object with those
* constraints must return <code>true</code>, or an
* <code>ExportException</code> is thrown.
*
* @param methods a collection of {@link Method} instances for the
* remote methods
* @param impl the remote object
* @param serverCaps the transport capabilities of the server
* @param serverConstraints the server constraints, or
* <code>null</code>
* @param permClass the permission class, or <code>null</code>
* @param policy the group policy, or <code>null</code>
* @param localAccessCheck if <code>true</code>, calls are only
* accepted from the local host
* @param loader the class loader, or <code>null</code>
* @throws IllegalArgumentException if <code>impl</code> is not an
* instance of {@link ActivationSystem} or if the permission class is
* abstract, is not a subclass of {@link java.security.Permission},
* or does not have a public constructor that has either one
* <code>String</code> parameter or one {@link Method} parameter and
* has no declared exceptions, or if any element of
* <code>methods</code> is not a {@link Method} instance
* @throws NullPointerException if <code>impl</code>,
* <code>methods</code> or <code>serverCaps</code> is
* <code>null</code>, or if <code>methods</code> contains a
* <code>null</code> element
* @throws ExportException if any of the possible server constraints
* cannot be satisfied according to the specified server capabilities
**/
public SystemDispatcher(Collection methods,
Remote impl,
ServerCapabilities serverCaps,
MethodConstraints serverConstraints,
Class permClass,
GroupPolicy policy,
boolean localAccessCheck,
ClassLoader loader)
throws ExportException
{
super(methods, serverCaps, serverConstraints, permClass, loader);
if (impl == null) {
throw new NullPointerException("impl is null");
}
if (!(impl instanceof ActivationSystem)) {
throw new IllegalArgumentException(
"impl not an ActivationSystem instance");
}
this.policy = policy;
this.localAccessCheck = localAccessCheck;
}
/**
* Checks that the client is calling from the local host.
*
* @throws java.security.AccessControlException if the client is not
* calling from the local host
*/
protected void checkAccess(Remote impl,
Method method,
InvocationConstraints constraints,
Collection context)
{
if (localAccessCheck) {
LocalAccess.check();
} else {
super.checkAccess(impl, method, constraints, context);
}
}
/**
* Checks the group policy as necessary, and then calls the superclass
* <code>invoke</code> method with the same arguments, and returns
* the result. If the policy is not <code>null</code> and the
* specified method is <code>ActivationSystem.registerGroup</code> or
* <code>ActivationSystem.setActivationGroupDesc</code>, the policy
* is checked by calling its {@link GroupPolicy#checkGroup checkGroup}
* method with the <code>ActivationGroupDesc</code> argument.
*
* @throws SecurityException if the caller is not permitted to use
* the specified group descriptor
*/
protected Object invoke(Remote impl,
Method method,
Object[] args,
Collection context)
throws Throwable
{
if (policy != null) {
String op = method.getName();
if (op.equals("registerGroup") ||
op.equals("setActivationGroupDesc"))
{
policy.checkGroup(
(ActivationGroupDesc) args[args.length - 1]);
}
}
return super.invoke(impl, method, args, context);
}
}
}