001/**
002 * Copyright 2005-2018 The Kuali Foundation
003 *
004 * Licensed under the Educational Community License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 * http://www.opensource.org/licenses/ecl2.php
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 */
016package org.kuali.rice.krad.util;
017
018import org.kuali.rice.kew.api.KewApiServiceLocator;
019import org.kuali.rice.krad.UserSession;
020import org.kuali.rice.krad.data.KradDataServiceLocator;
021import org.kuali.rice.krad.datadictionary.DocumentEntry;
022import org.kuali.rice.krad.service.KRADServiceLocatorWeb;
023
024import java.util.concurrent.Callable;
025
026/**
027 * Exposes legacy detection functionality statically.
028 *
029 * @author Kuali Rice Team (rice.collab@kuali.org)
030 */
031public final class LegacyUtils {
032
033    private static LegacyDetector ld = new LegacyDetector(KradDataServiceLocator.getMetadataRepository(),
034            KRADServiceLocatorWeb.getDataDictionaryService());
035
036    private LegacyUtils() {
037        throw new UnsupportedOperationException(LegacyUtils.class + " should not be constructed");
038    }
039
040    /**
041     * Indicates whether the given type is managed by the legacy data framework. Note that it's possible for a given
042     * type to managed by both the legacy and the non-legacy data framework, in which case this method will return true
043     * as well.
044     *
045     * @param type the type to check
046     * @return true if managed by the legacy framework, false otherwise
047     */
048    public static boolean isLegacyManaged(Class<?> type) {
049        return ld.isLegacyManaged(type);
050    }
051
052    /**
053     * Indicates whether the given type is managed by the non-legacy data framework. Note that it's possible for a given
054     * type to managed by both the legacy and the non-legacy data framework, in which case this method will return true
055     * as well.
056     *
057     * @param type the type to check
058     * @return true if managed by the non-legacy krad-data framework, false otherwise
059     */
060    public static boolean isKradDataManaged(Class<?> type) {
061        return ld.isKradDataManaged(type);
062    }
063
064    /**
065     * Indicates whether or not the given DocumentEntry represents a legacy KNS document entry.
066     *
067     * @param documentEntry the document entry to check
068     * @return true if the given entry is a KNS entry, false otherwise
069     */
070    public static boolean isKnsDocumentEntry(DocumentEntry documentEntry) {
071        return "org.kuali.rice.kns.datadictionary".equals(documentEntry.getClass().getPackage().getName());
072    }
073
074    public static boolean isKnsEnabled() {
075        return ld.isKnsEnabled();
076    }
077
078    /**
079     * Return whether the legacy data framework is enabled
080     * @return whether the legacy data framework is enabled
081     */
082    public static boolean isLegacyDataFrameworkEnabled() {
083        return ld.isLegacyDataFrameworkEnabled();
084    }
085
086    /**
087     * Return whether objects of the given class should be handled via the legacy data framework
088     * @param dataObjectClass the data object class
089     * @return whether objects of the given class should be handled via the legacy data framework
090     */
091    public static boolean useLegacy(Class<?> dataObjectClass) {
092        return ld.useLegacy(dataObjectClass);
093    }
094
095    /**
096     * Return whether the object should be handled via the legacy data framework
097     * @param dataObject the data object
098     * @return whether the object should be handled via the legacy data framework
099     */
100    public static boolean useLegacyForObject(Object dataObject) {
101        return ld.useLegacyForObject(dataObject);
102    }
103
104    /**
105     * @return whether we are currently in a legacy calling context
106     */
107    public static boolean isInLegacyContext() {
108        return ld.isInLegacyContext();
109    }
110
111    public static void beginLegacyContext() {
112        ld.beginLegacyContext();
113    }
114
115    public static void endLegacyContext() {
116        ld.endLegacyContext();
117    }
118
119    /**
120     * Performs the specified {@link Callable} inside of the legacy context.
121     *
122     * @param callable the method to call inside of the new contexts
123     * @param <T> the return type of the callable
124     * @return the result of the callable
125     * @throws Exception any exception thrown during the execution of the context
126     */
127    public static <T> T doInLegacyContext(Callable<T> callable) throws Exception {
128        beginLegacyContext();
129        try {
130            return callable.call();
131        } finally {
132            endLegacyContext();
133        }
134    }
135
136    /**
137     * Performs the specified {@link Callable} inside of both the legacy context (if necessary as dependent on the
138     * {@code documentId}) and in new {@link GlobalVariables} as specified by the given {@code userSession}.
139     *
140     * @param documentId id of the document for which to establish the data context
141     * @param userSession the new user session to establish
142     * @param callable the method to call inside of the new contexts
143     * @param <T> the return type of the callable
144     * @return the result of the callable
145     * @throws Exception any exception thrown during the execution of the context
146     */
147    public static <T> T doInLegacyContext(String documentId, UserSession userSession, Callable<T> callable) throws Exception {
148        boolean inLegacyContext = establishLegacyDataContextIfNecessary(documentId);
149        try {
150            return GlobalVariables.doInNewGlobalVariables(userSession, callable);
151        } finally {
152            clearLegacyDataContextIfExists(inLegacyContext);
153        }
154    }
155
156    /**
157     * Establish a legacy data context if it deems that it's necessary to do so for the document being processed.
158     * Unfortunately for us here, there is really no easy way to tell if the original document was submitted from a
159     * legacy context (i.e. KNS + OJB) or if it was submitted from a non-legacy context.
160     *
161     * <p>This is really only a problem for us if the data object happens to be mapped and configured in both the legacy
162     * and non-legacy data frameworks (which may be the case while a conversion is in-progress). In the case that the
163     * document or the maintainable happens to be configured for both legacy and non-legacy data frameworks, the best we
164     * can do is use the non-legacy framework by default. We will, however, ensure that the document entry is not one of
165     * the KNS subclasses, as that will tell us that they have, in fact, converted the document over from KNS to KRAD.
166     * </p>
167     *
168     * @param documentId id of the document for which to establish the data context
169     * @return true if a legacy data context was established, false otherwise
170     */
171    private static boolean establishLegacyDataContextIfNecessary(String documentId) {
172        String documentTypeName = KewApiServiceLocator.getWorkflowDocumentService().getDocumentTypeName(documentId);
173        DocumentEntry documentEntry = KRADServiceLocatorWeb.getDocumentDictionaryService().getDocumentEntry(documentTypeName);
174
175        if (isKnsDocumentEntry(documentEntry)) {
176            beginLegacyContext();
177
178            return true;
179        }
180
181        return false;
182    }
183
184    /**
185     * If the given boolean is true, will end any existing legacy data context.
186     *
187     * @param inLegacyContext whether or not the legacy data context has been established
188     */
189    private static void clearLegacyDataContextIfExists(boolean inLegacyContext) {
190        if (inLegacyContext) {
191            endLegacyContext();
192        }
193    }
194
195}