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