com.haulmont.cuba.restapi.RestServicePermissions.java Source code

Java tutorial

Introduction

Here is the source code for com.haulmont.cuba.restapi.RestServicePermissions.java

Source

/*
 * Copyright (c) 2008-2016 Haulmont.
 *
 * 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 com.haulmont.cuba.restapi;

import com.haulmont.bali.util.Dom4j;
import com.haulmont.cuba.core.global.Resources;
import com.haulmont.cuba.core.sys.AppContext;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang.text.StrTokenizer;
import org.dom4j.Element;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.core.io.Resource;
import org.springframework.stereotype.Component;

import javax.annotation.Nullable;
import javax.inject.Inject;
import java.io.IOException;
import java.io.InputStream;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;

/**
 * Class holds an information about services that allowed to be invoked with REST API.
 * Configuration is loaded from {@code *-rest-services.xml} files.
 */
@Component(RestServicePermissions.NAME)
public class RestServicePermissions {

    public static final String NAME = "cuba_RestServicePermissions";

    public static final String CUBA_REST_SERVICES_CONFIG_PROP_NAME = "cuba.restServicesConfig";

    private final Logger log = LoggerFactory.getLogger(RestServicePermissions.class);

    @Inject
    protected Resources resources;

    protected Map<String, Set<String>> serviceMethods = new ConcurrentHashMap<>();

    protected volatile boolean initialized;

    protected ReadWriteLock lock = new ReentrantReadWriteLock();

    /**
     * Checks whether method of service is allowed to be invoked with REST API
     */
    public boolean isPermitted(String serviceName, String methodName) {
        lock.readLock().lock();
        try {
            checkInitialized();
            Set<String> methods = serviceMethods.get(serviceName);
            return methods != null && methods.contains(methodName);
        } finally {
            lock.readLock().unlock();
        }
    }

    protected void checkInitialized() {
        if (!initialized) {
            lock.readLock().unlock();
            lock.writeLock().lock();
            try {
                if (!initialized) {
                    init();
                    initialized = true;
                }
            } finally {
                lock.readLock().lock();
                lock.writeLock().unlock();
            }
        }
    }

    protected void init() {
        String configName = AppContext.getProperty(CUBA_REST_SERVICES_CONFIG_PROP_NAME);
        StrTokenizer tokenizer = new StrTokenizer(configName);
        for (String location : tokenizer.getTokenArray()) {
            Resource resource = resources.getResource(location);
            if (resource.exists()) {
                InputStream stream = null;
                try {
                    stream = resource.getInputStream();
                    loadConfig(Dom4j.readDocument(stream).getRootElement());
                } catch (IOException e) {
                    throw new RuntimeException(e);
                } finally {
                    IOUtils.closeQuietly(stream);
                }
            } else {
                log.warn("Resource " + location + " not found, ignore it");
            }
        }
    }

    protected void loadConfig(Element rootElem) {
        for (Element serviceElem : Dom4j.elements(rootElem, "service")) {
            String serviceName = serviceElem.attributeValue("name");

            for (Element methodElem : Dom4j.elements(serviceElem, "method")) {
                String methodName = methodElem.attributeValue("name");
                addServiceMethod(serviceName, methodName);
            }
        }
    }

    protected void addServiceMethod(String serviceName, String methodName) {
        Set<String> methods = serviceMethods.get(serviceName);
        if (methods == null) {
            methods = new HashSet<>();
            serviceMethods.put(serviceName, methods);
        }
        methods.add(methodName);
    }

    public List<ServiceInfo> getServiceInfos() {
        lock.readLock().lock();
        try {
            checkInitialized();
            List<ServiceInfo> infos = new ArrayList<>();
            for (Map.Entry<String, Set<String>> entry : serviceMethods.entrySet()) {
                infos.add(new ServiceInfo(entry.getKey(), new HashSet<>(entry.getValue())));
            }
            return infos;
        } finally {
            lock.readLock().unlock();
        }
    }

    @Nullable
    public ServiceInfo getServiceInfo(String serviceName) {
        lock.readLock().lock();
        try {
            checkInitialized();
            Set<String> methods = serviceMethods.get(serviceName);
            if (methods == null) {
                return null;
            }
            return new ServiceInfo(serviceName, methods);
        } finally {
            lock.readLock().unlock();
        }
    }

    /**
     * Class stores an information about the service permitted for REST API
     */
    public static class ServiceInfo {
        private String service;
        private Set<String> methods;

        public ServiceInfo(String service, Set<String> methods) {
            this.service = service;
            this.methods = methods;
        }

        public String getService() {
            return service;
        }

        public void setService(String service) {
            this.service = service;
        }

        public Set<String> getMethods() {
            return methods;
        }

        public void setMethods(Set<String> methods) {
            this.methods = methods;
        }
    }
}