001    /**
002     * Copyright (c) 2000-present Liferay, Inc. All rights reserved.
003     *
004     * This library is free software; you can redistribute it and/or modify it under
005     * the terms of the GNU Lesser General Public License as published by the Free
006     * Software Foundation; either version 2.1 of the License, or (at your option)
007     * any later version.
008     *
009     * This library is distributed in the hope that it will be useful, but WITHOUT
010     * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
011     * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
012     * details.
013     */
014    
015    package com.liferay.portal.dao.orm.hibernate;
016    
017    import com.liferay.portal.kernel.annotation.ImplementationClassName;
018    import com.liferay.portal.kernel.concurrent.ConcurrentReferenceKeyHashMap;
019    import com.liferay.portal.kernel.dao.orm.DynamicQuery;
020    import com.liferay.portal.kernel.dao.orm.DynamicQueryFactory;
021    import com.liferay.portal.kernel.log.Log;
022    import com.liferay.portal.kernel.log.LogFactoryUtil;
023    import com.liferay.portal.kernel.memory.FinalizeManager;
024    import com.liferay.portal.kernel.security.pacl.permission.PortalRuntimePermission;
025    import com.liferay.portal.security.lang.DoPrivilegedUtil;
026    
027    import java.security.PrivilegedAction;
028    
029    import java.util.HashMap;
030    import java.util.Map;
031    import java.util.concurrent.ConcurrentMap;
032    
033    import org.hibernate.criterion.DetachedCriteria;
034    
035    /**
036     * @author Brian Wing Shun Chan
037     */
038    public class DynamicQueryFactoryImpl implements DynamicQueryFactory {
039    
040            @Override
041            public DynamicQuery forClass(Class<?> clazz) {
042                    clazz = getImplClass(clazz, null);
043    
044                    return DoPrivilegedUtil.wrap(
045                            new DynamicQueryPrivilegedAction(clazz, null));
046            }
047    
048            @Override
049            public DynamicQuery forClass(Class<?> clazz, ClassLoader classLoader) {
050                    clazz = getImplClass(clazz, classLoader);
051    
052                    return DoPrivilegedUtil.wrap(
053                            new DynamicQueryPrivilegedAction(clazz, null));
054            }
055    
056            @Override
057            public DynamicQuery forClass(Class<?> clazz, String alias) {
058                    clazz = getImplClass(clazz, null);
059    
060                    return DoPrivilegedUtil.wrap(
061                            new DynamicQueryPrivilegedAction(clazz, alias));
062            }
063    
064            @Override
065            public DynamicQuery forClass(
066                    Class<?> clazz, String alias, ClassLoader classLoader) {
067    
068                    clazz = getImplClass(clazz, classLoader);
069    
070                    return DoPrivilegedUtil.wrap(
071                            new DynamicQueryPrivilegedAction(clazz, alias));
072            }
073    
074            protected Class<?> getImplClass(Class<?> clazz, ClassLoader classLoader) {
075                    ImplementationClassName implementationClassName = clazz.getAnnotation(
076                            ImplementationClassName.class);
077    
078                    if (implementationClassName == null) {
079                            String className = clazz.getName();
080    
081                            if (!className.endsWith("Impl")) {
082                                    _log.error("Unable find model for " + clazz);
083                            }
084    
085                            PortalRuntimePermission.checkDynamicQuery(clazz);
086    
087                            return clazz;
088                    }
089    
090                    Class<?> implClass = clazz;
091    
092                    String implClassName = implementationClassName.value();
093    
094                    try {
095                            implClass = getImplClass(implClassName, classLoader);
096                    }
097                    catch (Exception e1) {
098                            if (classLoader != _portalClassLoader) {
099                                    try {
100                                            implClass = getImplClass(implClassName, _portalClassLoader);
101                                    }
102                                    catch (Exception e2) {
103                                            _log.error("Unable find model " + implClassName, e2);
104                                    }
105                            }
106                            else {
107                                    _log.error("Unable find model " + implClassName, e1);
108                            }
109                    }
110    
111                    PortalRuntimePermission.checkDynamicQuery(implClass);
112    
113                    return implClass;
114            }
115    
116            protected Class<?> getImplClass(
117                            String implClassName, ClassLoader classLoader)
118                    throws ClassNotFoundException {
119    
120                    Map<String, Class<?>> classes = _classes.get(classLoader);
121    
122                    if (classes == null) {
123                            classes = new HashMap<>();
124    
125                            _classes.put(classLoader, classes);
126                    }
127    
128                    Class<?> clazz = classes.get(implClassName);
129    
130                    if (clazz == null) {
131                            clazz = classLoader.loadClass(implClassName);
132    
133                            classes.put(implClassName, clazz);
134                    }
135    
136                    return clazz;
137            }
138    
139            private static final Log _log = LogFactoryUtil.getLog(
140                    DynamicQueryFactoryImpl.class);
141    
142            private static final
143                    ConcurrentMap<ClassLoader, Map<String, Class<?>>> _classes =
144                            new ConcurrentReferenceKeyHashMap<>(
145                                    FinalizeManager.WEAK_REFERENCE_FACTORY);
146    
147            private final ClassLoader _portalClassLoader =
148                    DynamicQueryFactoryImpl.class.getClassLoader();
149    
150            private static class DynamicQueryPrivilegedAction
151                    implements PrivilegedAction<DynamicQuery> {
152    
153                    public DynamicQueryPrivilegedAction(Class<?> clazz, String alias) {
154                            _clazz = clazz;
155                            _alias = alias;
156                    }
157    
158                    @Override
159                    public DynamicQuery run() {
160                            if (_alias != null) {
161                                    return new DynamicQueryImpl(
162                                            DetachedCriteria.forClass(_clazz, _alias));
163                            }
164    
165                            return new DynamicQueryImpl(DetachedCriteria.forClass(_clazz));
166                    }
167    
168                    private final String _alias;
169                    private final Class<?> _clazz;
170    
171            }
172    
173    }