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.search.buffer;
016    
017    import com.liferay.portal.NoSuchModelException;
018    import com.liferay.portal.kernel.lar.ExportImportThreadLocal;
019    import com.liferay.portal.kernel.log.Log;
020    import com.liferay.portal.kernel.log.LogFactoryUtil;
021    import com.liferay.portal.kernel.search.Indexer;
022    import com.liferay.portal.kernel.search.SearchEngineUtil;
023    import com.liferay.portal.kernel.util.MethodKey;
024    import com.liferay.portal.kernel.util.Validator;
025    import com.liferay.portal.model.BaseModel;
026    import com.liferay.portal.model.ClassedModel;
027    import com.liferay.portal.model.ResourcedModel;
028    import com.liferay.portal.security.auth.CompanyThreadLocal;
029    import com.liferay.portal.service.PersistedModelLocalService;
030    import com.liferay.portal.service.PersistedModelLocalServiceRegistry;
031    import com.liferay.portal.util.PropsValues;
032    
033    import java.lang.reflect.InvocationHandler;
034    import java.lang.reflect.Method;
035    
036    import java.util.Arrays;
037    import java.util.Collection;
038    
039    /**
040     * @author Michael C. Han
041     */
042    public class BufferedIndexerInvocationHandler implements InvocationHandler {
043    
044            public BufferedIndexerInvocationHandler(
045                    Indexer indexer,
046                    PersistedModelLocalServiceRegistry persistedModelLocalServiceRegistry) {
047    
048                    _indexer = indexer;
049                    _persistedModelLocalServiceRegistry =
050                            persistedModelLocalServiceRegistry;
051            }
052    
053            @Override
054            public Object invoke(Object proxy, Method method, Object[] args)
055                    throws Throwable {
056    
057                    IndexerRequestBuffer indexerRequestBuffer = IndexerRequestBuffer.get();
058    
059                    if ((!Validator.equals(method.getName(), "delete") &&
060                             !Validator.equals(method.getName(), "reindex")) ||
061                            (args.length == 0) || (args.length > 2) ||
062                            (indexerRequestBuffer == null)) {
063    
064                            return method.invoke(_indexer, args);
065                    }
066    
067                    if (SearchEngineUtil.isIndexReadOnly()) {
068                            if (_log.isDebugEnabled()) {
069                                    _log.debug(
070                                            "Skipping indexer request buffer because index is read " +
071                                                    "only");
072                            }
073    
074                            return null;
075                    }
076    
077                    if (ExportImportThreadLocal.isImportInProcess() &&
078                            Validator.equals(method.getName(), "reindex")) {
079    
080                            if (_log.isDebugEnabled()) {
081                                    _log.debug(
082                                            "Skipping indexer request buffer because import is in " +
083                                                    "process");
084                            }
085    
086                            return null;
087                    }
088    
089                    if (CompanyThreadLocal.isDeleteInProcess()) {
090                            if (_log.isDebugEnabled()) {
091                                    _log.debug(
092                                            "Skipping indexer request buffer because a company " +
093                                                    "delete is in process");
094                            }
095    
096                            return null;
097                    }
098    
099                    Class<?> args0Class = args[0].getClass();
100    
101                    if (!(args[0] instanceof BaseModel) &&
102                            !(args[0] instanceof ClassedModel) &&
103                            !((args[0] instanceof Long) && (args.length == 1)) &&
104                            !(args[0] instanceof long[]) &&
105                            !(args0Class.isArray() ||
106                              Collection.class.isAssignableFrom(args0Class)) &&
107                            !((args.length == 2) && (args[0] instanceof String) &&
108                              Validator.equals(args[1].getClass(), Long.class))) {
109    
110                            return method.invoke(_indexer, args);
111                    }
112    
113                    if (args[0] instanceof ResourcedModel &&
114                            args[0] instanceof ClassedModel &&
115                            Validator.equals(method.getName(), "reindex")) {
116    
117                            MethodKey methodKey = new MethodKey(
118                                    Indexer.class, method.getName(), String.class, Long.TYPE);
119    
120                            ClassedModel classedModel = (ClassedModel)args[0];
121                            ResourcedModel resourcedModel = (ResourcedModel)args[0];
122    
123                            bufferRequest(
124                                    methodKey, classedModel.getModelClassName(),
125                                    resourcedModel.getResourcePrimKey(), indexerRequestBuffer);
126                    }
127                    else if (args[0] instanceof ClassedModel) {
128                            MethodKey methodKey = new MethodKey(
129                                    Indexer.class, method.getName(), Object.class);
130    
131                            bufferRequest(methodKey, args[0], indexerRequestBuffer);
132                    }
133                    else if (args.length == 2) {
134                            MethodKey methodKey = new MethodKey(
135                                    Indexer.class, method.getName(), String.class, Long.TYPE);
136    
137                            String className = (String)args[0];
138                            Long classPK = (Long)args[1];
139    
140                            PersistedModelLocalService persistedModelLocalService =
141                                    _persistedModelLocalServiceRegistry.
142                                            getPersistedModelLocalService(className);
143    
144                            try {
145                                    Object obj = persistedModelLocalService.getPersistedModel(
146                                            classPK);
147    
148                                    if (obj instanceof ResourcedModel) {
149                                            ResourcedModel resourcedModel = (ResourcedModel)obj;
150    
151                                            classPK = resourcedModel.getResourcePrimKey();
152                                    }
153                            }
154                            catch (Exception e) {
155                                    if (_log.isDebugEnabled()) {
156                                            _log.debug(
157                                                    "Unable to get resource primary key for class " +
158                                                            className + " with primary key " + classPK);
159    
160                                            if (!(e instanceof NoSuchModelException)) {
161                                                    _log.debug(e, e);
162                                            }
163                                    }
164                            }
165    
166                            bufferRequest(methodKey, className, classPK, indexerRequestBuffer);
167                    }
168                    else if (args[0] instanceof Long) {
169                            MethodKey methodKey = new MethodKey(
170                                    Indexer.class, method.getName(), String.class, Long.TYPE);
171    
172                            String className = _indexer.getClassNames()[0];
173                            Long classPK = (Long)args[0];
174    
175                            bufferRequest(methodKey, className, classPK, indexerRequestBuffer);
176                    }
177                    else if (args[0] instanceof long[]) {
178                            MethodKey methodKey = new MethodKey(
179                                    Indexer.class, method.getName(), String.class, Long.TYPE);
180    
181                            long[] primaryKeyArray = (long[])args[0];
182    
183                            for (int i = 0; i<primaryKeyArray.length; i++) {
184                                    String className = _indexer.getClassNames()[0];
185                                    Long classPK = (Long)primaryKeyArray[i];
186    
187                                    bufferRequest(
188                                            methodKey, className, classPK, indexerRequestBuffer);
189                            }
190                    }
191                    else {
192                            MethodKey methodKey = new MethodKey(
193                                    Indexer.class, method.getName(), Object.class);
194    
195                            Collection<Object> objects;
196    
197                            try {
198                                    if (args0Class.isArray()) {
199                                            objects = Arrays.asList((Object[])args[0]);
200                                    }
201                                    else {
202                                            objects = (Collection<Object>)args[0];
203                                    }
204    
205                                    for (Object object : objects) {
206                                            if (!(object instanceof ClassedModel)) {
207                                                    objects = null;
208    
209                                                    break;
210                                            }
211                                    }
212                            }
213                            catch (Exception e) {
214                                    if (_log.isDebugEnabled()) {
215                                            if (_log.isDebugEnabled()) {
216                                                    _log.debug(
217                                                            "Unexpected error buffering indexing request", e);
218                                            }
219                                    }
220    
221                                    objects = null;
222                            }
223    
224                            if (objects == null) {
225                                    return method.invoke(_indexer, args);
226                            }
227    
228                            for (Object object : objects) {
229                                    bufferRequest(methodKey, object, indexerRequestBuffer);
230                            }
231                    }
232    
233                    return null;
234            }
235    
236            protected void bufferRequest(
237                            MethodKey methodKey, Object object,
238                            IndexerRequestBuffer indexerRequestBuffer)
239                    throws Exception {
240    
241                    BaseModel<?> baseModel = (BaseModel<?>)object;
242    
243                    ClassedModel classedModel = (ClassedModel)baseModel.clone();
244    
245                    IndexerRequest indexerRequest = new IndexerRequest(
246                            methodKey.getMethod(), classedModel, _indexer);
247    
248                    doBufferRequest(indexerRequest, indexerRequestBuffer);
249            }
250    
251            protected void bufferRequest(
252                            MethodKey methodKey, String className, Long classPK,
253                            IndexerRequestBuffer indexerRequestBuffer)
254                    throws Exception {
255    
256                    IndexerRequest indexerRequest = new IndexerRequest(
257                            methodKey.getMethod(), _indexer, className, classPK);
258    
259                    doBufferRequest(indexerRequest, indexerRequestBuffer);
260            }
261    
262            protected void doBufferRequest(
263                            IndexerRequest indexerRequest,
264                            IndexerRequestBuffer indexerRequestBuffer)
265                    throws Exception {
266    
267                    if (BufferOverflowThreadLocal.isOverflowMode()) {
268                            indexerRequest.execute();
269    
270                            return;
271                    }
272    
273                    indexerRequestBuffer.add(indexerRequest);
274    
275                    if (indexerRequestBuffer.size() >
276                                    PropsValues.INDEX_REQUEST_BUFFER_MAX_SIZE) {
277    
278                            IndexerRequestBufferUtil.bufferOverflowed(
279                                    indexerRequestBuffer,
280                                    PropsValues.INDEX_REQUEST_BUFFER_MAX_SIZE);
281                    }
282            }
283    
284            private static Log _log = LogFactoryUtil.getLog(
285                    BufferedIndexerInvocationHandler.class);
286    
287            private final Indexer _indexer;
288            private final PersistedModelLocalServiceRegistry
289                    _persistedModelLocalServiceRegistry;
290    
291    }