001    /**
002     * Copyright (c) 2000-2013 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.kernel.resiliency.spi.remote;
016    
017    import com.liferay.portal.kernel.deploy.hot.DependencyManagementThreadLocal;
018    import com.liferay.portal.kernel.log.Log;
019    import com.liferay.portal.kernel.log.LogFactoryUtil;
020    import com.liferay.portal.kernel.nio.intraband.RegistrationReference;
021    import com.liferay.portal.kernel.nio.intraband.welder.Welder;
022    import com.liferay.portal.kernel.nio.intraband.welder.WelderFactoryUtil;
023    import com.liferay.portal.kernel.process.ProcessCallable;
024    import com.liferay.portal.kernel.process.ProcessException;
025    import com.liferay.portal.kernel.process.ProcessExecutor;
026    import com.liferay.portal.kernel.process.log.ProcessOutputStream;
027    import com.liferay.portal.kernel.resiliency.mpi.MPI;
028    import com.liferay.portal.kernel.resiliency.mpi.MPIHelperUtil;
029    import com.liferay.portal.kernel.resiliency.spi.SPI;
030    import com.liferay.portal.kernel.resiliency.spi.SPIConfiguration;
031    import com.liferay.portal.kernel.resiliency.spi.agent.SPIAgent;
032    import com.liferay.portal.kernel.resiliency.spi.agent.SPIAgentFactoryUtil;
033    import com.liferay.portal.kernel.resiliency.spi.provider.SPISynchronousQueueUtil;
034    import com.liferay.portal.kernel.util.PropsKeys;
035    import com.liferay.portal.kernel.util.ReflectionUtil;
036    
037    import java.io.IOException;
038    import java.io.ObjectInputStream;
039    import java.io.ObjectOutputStream;
040    
041    import java.lang.reflect.Field;
042    
043    import java.rmi.Remote;
044    import java.rmi.RemoteException;
045    import java.rmi.server.UnicastRemoteObject;
046    
047    import java.util.UUID;
048    import java.util.concurrent.ConcurrentMap;
049    
050    /**
051     * @author Shuyang Zhou
052     */
053    public abstract class RemoteSPI implements ProcessCallable<SPI>, Remote, SPI {
054    
055            public RemoteSPI(SPIConfiguration spiConfiguration) {
056                    this.spiConfiguration = spiConfiguration;
057    
058                    mpi = MPIHelperUtil.getMPI();
059    
060                    UUID uuidObject = UUID.randomUUID();
061    
062                    uuid = uuidObject.toString();
063    
064                    welder = WelderFactoryUtil.createWelder();
065            }
066    
067            @Override
068            public SPI call() throws ProcessException {
069                    try {
070                            ProcessExecutor.ProcessContext.attach(
071                                    spiConfiguration.getSPIId(), spiConfiguration.getPingInterval(),
072                                    new SPIShutdownHook());
073    
074                            SPI spi = (SPI)UnicastRemoteObject.exportObject(this, 0);
075    
076                            RegisterCallback registerCallback = new RegisterCallback(uuid, spi);
077    
078                            ProcessOutputStream processOutputStream =
079                                    ProcessExecutor.ProcessContext.getProcessOutputStream();
080    
081                            processOutputStream.writeProcessCallable(registerCallback);
082    
083                            registrationReference = welder.weld(MPIHelperUtil.getIntraband());
084    
085                            ConcurrentMap<String, Object> attributes =
086                                    ProcessExecutor.ProcessContext.getAttributes();
087    
088                            attributes.put(SPI.SPI_INSTANCE_PUBLICATION_KEY, this);
089    
090                            return spi;
091                    }
092                    catch (RemoteException re) {
093                            throw new ProcessException("Failed to export SPI as RMI stub.", re);
094                    }
095                    catch (IOException ioe) {
096                            throw new ProcessException(ioe);
097                    }
098            }
099    
100            @Override
101            public MPI getMPI() {
102                    return mpi;
103            }
104    
105            @Override
106            public RegistrationReference getRegistrationReference() {
107                    return registrationReference;
108            }
109    
110            @Override
111            public SPIAgent getSPIAgent() {
112                    if (spiAgent == null) {
113                            spiAgent = SPIAgentFactoryUtil.createSPIAgent(
114                                    spiConfiguration, registrationReference);
115                    }
116    
117                    return spiAgent;
118            }
119    
120            @Override
121            public SPIConfiguration getSPIConfiguration() {
122                    return spiConfiguration;
123            }
124    
125            public String getUUID() {
126                    return uuid;
127            }
128    
129            public Welder getWelder() {
130                    return welder;
131            }
132    
133            @Override
134            public boolean isAlive() {
135                    return true;
136            }
137    
138            protected final MPI mpi;
139            protected RegistrationReference registrationReference;
140            protected transient volatile SPIAgent spiAgent;
141            protected final SPIConfiguration spiConfiguration;
142            protected final String uuid;
143            protected final Welder welder;
144    
145            protected static class RegisterCallback implements ProcessCallable<SPI> {
146    
147                    public RegisterCallback(String spiUUID, SPI spi) {
148                            _spiUUID = spiUUID;
149                            _spi = spi;
150                    }
151    
152                    @Override
153                    public SPI call() throws ProcessException {
154                            try {
155                                    SPISynchronousQueueUtil.notifySynchronousQueue(_spiUUID, _spi);
156                            }
157                            catch (InterruptedException ie) {
158                                    throw new ProcessException(ie);
159                            }
160    
161                            return _spi;
162                    }
163    
164                    private static final long serialVersionUID = 1L;
165    
166                    private final SPI _spi;
167                    private final String _spiUUID;
168    
169            }
170    
171            protected class SPIShutdownHook implements ProcessExecutor.ShutdownHook {
172    
173                    @Override
174                    public boolean shutdown(int shutdownCode, Throwable shutdownThrowable) {
175                            try {
176                                    RemoteSPI.this.stop();
177                            }
178                            catch (RemoteException re) {
179                                    _log.error("Unable to stop SPI", re);
180                            }
181    
182                            try {
183                                    RemoteSPI.this.destroy();
184                            }
185                            catch (RemoteException re) {
186                                    _log.error("Unable to destroy SPI", re);
187                            }
188    
189                            return true;
190                    }
191    
192            }
193    
194            private void readObject(ObjectInputStream objectInputStream)
195                    throws ClassNotFoundException, IOException {
196    
197                    objectInputStream.defaultReadObject();
198    
199                    System.setProperty(
200                            PropsKeys.INTRABAND_IMPL, objectInputStream.readUTF());
201                    System.setProperty(
202                            PropsKeys.INTRABAND_TIMEOUT_DEFAULT, objectInputStream.readUTF());
203                    System.setProperty(
204                            PropsKeys.INTRABAND_WELDER_IMPL, objectInputStream.readUTF());
205                    System.setProperty(
206                            "portal:" + PropsKeys.LIFERAY_HOME, objectInputStream.readUTF());
207    
208                    // Disable auto deploy
209    
210                    System.setProperty("portal:" + PropsKeys.AUTO_DEPLOY_ENABLED, "false");
211    
212                    // Disable cluster link
213    
214                    System.setProperty("portal:" + PropsKeys.CLUSTER_LINK_ENABLED, "false");
215    
216                    // Disable dependency management
217    
218                    try {
219                            Field enabledField = ReflectionUtil.getDeclaredField(
220                                    DependencyManagementThreadLocal.class, "_enabled");
221    
222                            enabledField.set(
223                                    null,
224                                    new ThreadLocal<Boolean>() {
225    
226                                            @Override
227                                            public Boolean get() {
228                                                    return Boolean.FALSE;
229                                            }
230    
231                                    });
232                    }
233                    catch (Exception e) {
234                            throw new IOException("Unable to disable dependency management", e);
235                    }
236    
237                    // Log4j log file postfix
238    
239                    System.setProperty("spi.id", "-" + spiConfiguration.getSPIId());
240            }
241    
242            private void writeObject(ObjectOutputStream objectOutputStream)
243                    throws IOException {
244    
245                    objectOutputStream.defaultWriteObject();
246    
247                    objectOutputStream.writeUTF(
248                            System.getProperty(PropsKeys.INTRABAND_IMPL));
249                    objectOutputStream.writeUTF(
250                            System.getProperty(PropsKeys.INTRABAND_TIMEOUT_DEFAULT));
251                    objectOutputStream.writeUTF(
252                            System.getProperty(PropsKeys.INTRABAND_WELDER_IMPL));
253                    objectOutputStream.writeUTF(System.getProperty(PropsKeys.LIFERAY_HOME));
254            }
255    
256            private static Log _log = LogFactoryUtil.getLog(RemoteSPI.class);
257    
258    }