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.increment;
016    
017    import com.liferay.portal.kernel.cache.key.CacheKeyGenerator;
018    import com.liferay.portal.kernel.cache.key.CacheKeyGeneratorUtil;
019    import com.liferay.portal.kernel.increment.BufferedIncrement;
020    import com.liferay.portal.kernel.increment.Increment;
021    import com.liferay.portal.kernel.increment.IncrementFactory;
022    import com.liferay.portal.kernel.transaction.TransactionCommitCallbackUtil;
023    import com.liferay.portal.kernel.util.StringUtil;
024    import com.liferay.portal.spring.aop.AnnotationChainableMethodAdvice;
025    
026    import java.io.Serializable;
027    
028    import java.lang.annotation.Annotation;
029    import java.lang.reflect.Method;
030    
031    import java.util.Map;
032    import java.util.concurrent.Callable;
033    import java.util.concurrent.ConcurrentHashMap;
034    import java.util.concurrent.ConcurrentMap;
035    
036    import org.aopalliance.intercept.MethodInvocation;
037    
038    /**
039     * @author Zsolt Berentey
040     * @author Shuyang Zhou
041     */
042    public class BufferedIncrementAdvice
043            extends AnnotationChainableMethodAdvice<BufferedIncrement> {
044    
045            @Override
046            @SuppressWarnings("rawtypes")
047            public Object before(MethodInvocation methodInvocation) throws Throwable {
048                    BufferedIncrement bufferedIncrement = findAnnotation(methodInvocation);
049    
050                    if (bufferedIncrement == _nullBufferedIncrement) {
051                            return null;
052                    }
053    
054                    String configuration = bufferedIncrement.configuration();
055    
056                    BufferedIncrementConfiguration bufferedIncrementConfiguration =
057                            _bufferedIncrementConfigurations.get(configuration);
058    
059                    if (bufferedIncrementConfiguration == null) {
060                            bufferedIncrementConfiguration = new BufferedIncrementConfiguration(
061                                    configuration);
062    
063                            _bufferedIncrementConfigurations.put(
064                                    configuration, bufferedIncrementConfiguration);
065                    }
066    
067                    if (!bufferedIncrementConfiguration.isEnabled()) {
068                            return nullResult;
069                    }
070    
071                    Method method = methodInvocation.getMethod();
072    
073                    BufferedIncrementProcessor bufferedIncrementProcessor =
074                            _bufferedIncrementProcessors.get(method);
075    
076                    if (bufferedIncrementProcessor == null) {
077                            bufferedIncrementProcessor = new BufferedIncrementProcessor(
078                                    bufferedIncrementConfiguration, method);
079    
080                            BufferedIncrementProcessor previousBufferedIncrementProcessor =
081                                    _bufferedIncrementProcessors.putIfAbsent(
082                                            method, bufferedIncrementProcessor);
083    
084                            if (previousBufferedIncrementProcessor != null) {
085                                    bufferedIncrementProcessor = previousBufferedIncrementProcessor;
086                            }
087                    }
088    
089                    Object[] arguments = methodInvocation.getArguments();
090    
091                    Object value = arguments[arguments.length - 1];
092    
093                    CacheKeyGenerator cacheKeyGenerator =
094                            CacheKeyGeneratorUtil.getCacheKeyGenerator(
095                                    BufferedIncrementAdvice.class.getName());
096    
097                    for (int i = 0; i < arguments.length - 1; i++) {
098                            cacheKeyGenerator.append(StringUtil.toHexString(arguments[i]));
099                    }
100    
101                    Serializable batchKey = cacheKeyGenerator.finish();
102    
103                    Increment<?> increment = IncrementFactory.createIncrement(
104                            bufferedIncrement.incrementClass(), value);
105    
106                    final BufferedIncrementProcessor callbackBufferedIncrementProcessor =
107                            bufferedIncrementProcessor;
108    
109                    final BufferedIncreasableEntry bufferedIncreasableEntry =
110                            new BufferedIncreasableEntry(methodInvocation, batchKey, increment);
111    
112                    TransactionCommitCallbackUtil.registerCallback(
113                            new Callable<Void>() {
114    
115                                    @Override
116                                    public Void call() throws Exception {
117                                            callbackBufferedIncrementProcessor.process(
118                                                    bufferedIncreasableEntry);
119    
120                                            return null;
121                                    }
122    
123                            });
124    
125                    return nullResult;
126            }
127    
128            public void destroy() {
129                    for (BufferedIncrementProcessor bufferedIncrementProcessor :
130                                    _bufferedIncrementProcessors.values()) {
131    
132                            bufferedIncrementProcessor.destroy();
133                    }
134            }
135    
136            @Override
137            public BufferedIncrement getNullAnnotation() {
138                    return _nullBufferedIncrement;
139            }
140    
141            private static final BufferedIncrement _nullBufferedIncrement =
142                    new BufferedIncrement() {
143    
144                            @Override
145                            public Class<? extends Annotation> annotationType() {
146                                    return BufferedIncrement.class;
147                            }
148    
149                            @Override
150                            public String configuration() {
151                                    return "default";
152                            }
153    
154                            @Override
155                            public Class<? extends Increment<?>> incrementClass() {
156                                    return null;
157                            }
158    
159                    };
160    
161            private final Map<String, BufferedIncrementConfiguration>
162                    _bufferedIncrementConfigurations = new ConcurrentHashMap<>();
163            private final ConcurrentMap<Method, BufferedIncrementProcessor>
164                    _bufferedIncrementProcessors = new ConcurrentHashMap<>();
165    
166    }