001/*
002 * Licensed to the Apache Software Foundation (ASF) under one
003 * or more contributor license agreements. See the NOTICE file
004 * distributed with this work for additional information
005 * regarding copyright ownership. The ASF licenses this file
006 * to you under the Apache License, Version 2.0 (the
007 * "License"); you may not use this file except in compliance
008 * with the License. You may obtain a copy of the License at
009 *
010 * http://www.apache.org/licenses/LICENSE-2.0
011 *
012 * Unless required by applicable law or agreed to in writing,
013 * software distributed under the License is distributed on an
014 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
015 * KIND, either express or implied. See the License for the
016 * specific language governing permissions and limitations
017 * under the License.
018 */
019package org.apache.commons.weaver.privilizer;
020
021import java.lang.annotation.ElementType;
022import java.util.LinkedHashSet;
023import java.util.Set;
024
025import org.apache.commons.lang3.Validate;
026import org.apache.commons.weaver.model.ScanRequest;
027import org.apache.commons.weaver.model.Scanner;
028import org.apache.commons.weaver.model.WeavableClass;
029import org.apache.commons.weaver.model.WeaveEnvironment;
030import org.apache.commons.weaver.model.WeaveInterest;
031import org.apache.commons.weaver.spi.Weaver;
032
033/**
034 * Privilizer {@link Weaver} implementation.
035 */
036public class PrivilizerWeaver implements Weaver {
037    @Override
038    public boolean process(final WeaveEnvironment weaveEnvironment, final Scanner scanner) {
039        final Privilizer privilizer = new Privilizer(weaveEnvironment);
040
041        final Set<Class<?>> privilizedTypes = new LinkedHashSet<Class<?>>();
042
043        // handle blueprints:
044        for (final WeavableClass<?> type : scanner.scan(
045            new ScanRequest().add(WeaveInterest.of(Privilizing.class, ElementType.TYPE))).getClasses()) {
046
047            final Class<?> target = type.getTarget();
048            if (privilizedTypes.add(target) && validateRequest(privilizer, type)) {
049                privilizer.blueprint(target, type.getAnnotation(Privilizing.class));
050            }
051        }
052
053        // handle remaining classes declaring @Privileged methods:
054
055        for (final WeavableClass<?> type : scanner.scan(
056            new ScanRequest().add(WeaveInterest.of(Privileged.class, ElementType.METHOD))).getClasses()) {
057            final Class<?> target = type.getTarget();
058            if (privilizedTypes.add(target) && validateRequest(privilizer, type)) {
059                privilizer.privilize(target);
060            }
061        }
062        return !privilizedTypes.isEmpty();
063    }
064
065    /**
066     * Validate a weaving request for a given target type.
067     * @param privilizer whose configuration to consult
068     * @param type target
069     * @return whether weaving should proceed
070     * @throws IllegalStateException if class has already been woven with some other policy
071     */
072    private boolean validateRequest(final Privilizer privilizer, final WeavableClass<?> type) {
073        final Privilized marker = type.getAnnotation(Privilized.class);
074        if (marker == null) {
075            return privilizer.policy != Policy.NEVER;
076        }
077        Validate.validState(privilizer.policy.name().equals(marker.value()), "%s already privilized with policy %s",
078            type.getTarget().getName(), marker.value());
079
080        return false;
081    }
082}