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.shiro.config;
020
021import org.apache.shiro.io.ResourceUtils;
022import org.apache.shiro.util.AbstractFactory;
023import org.apache.shiro.util.CollectionUtils;
024import org.apache.shiro.util.Factory;
025import org.slf4j.Logger;
026import org.slf4j.LoggerFactory;
027
028import java.util.HashMap;
029import java.util.Map;
030
031/**
032 * Base support class for {@link Factory} implementations that generate their instance(s) based on
033 * {@link Ini} configuration.
034 *
035 * @since 1.0
036 * @deprecated use Shiro's {@code Environment} mechanisms instead.
037 */
038@Deprecated
039public abstract class IniFactorySupport<T> extends AbstractFactory<T> {
040
041    public static final String DEFAULT_INI_RESOURCE_PATH = "classpath:shiro.ini";
042
043    private static transient final Logger log = LoggerFactory.getLogger(IniFactorySupport.class);
044
045    private Ini ini;
046
047    private Map<String, ?> defaultBeans;
048
049    protected IniFactorySupport() {
050    }
051
052    protected IniFactorySupport(Ini ini) {
053        this.ini = ini;
054    }
055
056    public Ini getIni() {
057        return ini;
058    }
059
060    public void setIni(Ini ini) {
061        this.ini = ini;
062    }
063
064    /**
065     * Returns a mapping of String to bean representing the default set of object used by the factory.
066     * These beans can be used by this factory in conjunction with objects parsed from the INI configuration.
067     * @return A Map of default objects, or <code>null</code>.
068     * @since 1.4
069     */
070    protected Map<String, ?> getDefaults() {
071        return defaultBeans;
072    }
073
074    /**
075     * Sets the default objects used by this factory. These defaults may be used in conjunction with the INI
076     * configuration.
077     * @param defaultBeans String to object mapping used for default configuration in this factory.
078     * @since 1.4
079     */
080    public void setDefaults(Map<String, ?> defaultBeans) {
081        this.defaultBeans = defaultBeans;
082    }
083
084    /**
085     * Returns a new Ini instance created from the default {@code classpath:shiro.ini} file, or {@code null} if
086     * the file does not exist.
087     *
088     * @return a new Ini instance created from the default {@code classpath:shiro.ini} file, or {@code null} if
089     *         the file does not exist.
090     */
091    public static Ini loadDefaultClassPathIni() {
092        Ini ini = null;
093        if (ResourceUtils.resourceExists(DEFAULT_INI_RESOURCE_PATH)) {
094            log.debug("Found shiro.ini at the root of the classpath.");
095            ini = new Ini();
096            ini.loadFromPath(DEFAULT_INI_RESOURCE_PATH);
097            if (CollectionUtils.isEmpty(ini)) {
098                log.warn("shiro.ini found at the root of the classpath, but it did not contain any data.");
099            }
100        }
101        return ini;
102    }
103
104    /**
105     * Tries to resolve the Ini instance to use for configuration.  This implementation functions as follows:
106     * <ol>
107     * <li>The {@code Ini} instance returned from {@link #getIni()} will be returned if it is not null or empty.</li>
108     * <li>If {@link #getIni()} is {@code null} or empty, this implementation will attempt to find and load the
109     * {@link #loadDefaultClassPathIni() default class path Ini}.</li>
110     * <li>If neither of the two attempts above returns an instance, {@code null} is returned</li>
111     * </ol>
112     *
113     * @return the Ini instance to use for configuration.
114     */
115    protected Ini resolveIni() {
116        Ini ini = getIni();
117        if (CollectionUtils.isEmpty(ini)) {
118            log.debug("Null or empty Ini instance.  Falling back to the default {} file.", DEFAULT_INI_RESOURCE_PATH);
119            ini = loadDefaultClassPathIni();
120        }
121        return ini;
122    }
123
124    /**
125     * Creates a new object instance by using a configured INI source.  This implementation functions as follows:
126     * <ol>
127     * <li>{@link #resolveIni() Resolve} the {@code Ini} source to use for configuration.</li>
128     * <li>If there was no resolved Ini source, create and return a simple default instance via the
129     * {@link #createDefaultInstance()} method.</li>
130     * </ol>
131     *
132     * @return a new {@code SecurityManager} instance by using a configured INI source.
133     */
134    public T createInstance() {
135        Ini ini = resolveIni();
136
137        T instance;
138
139        if (CollectionUtils.isEmpty(ini)) {
140            log.debug("No populated Ini available.  Creating a default instance.");
141            instance = createDefaultInstance();
142            if (instance == null) {
143                String msg = getClass().getName() + " implementation did not return a default instance in " +
144                        "the event of a null/empty Ini configuration.  This is required to support the " +
145                        "Factory interface.  Please check your implementation.";
146                throw new IllegalStateException(msg);
147            }
148        } else {
149            log.debug("Creating instance from Ini [" + ini + "]");
150            instance = createInstance(ini);
151            if (instance == null) {
152                String msg = getClass().getName() + " implementation did not return a constructed instance from " +
153                        "the createInstance(Ini) method implementation.";
154                throw new IllegalStateException(msg);
155            }
156        }
157
158        return instance;
159    }
160
161    protected abstract T createInstance(Ini ini);
162
163    protected abstract T createDefaultInstance();
164}