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.provider;
016    
017    import com.liferay.portal.kernel.nio.intraband.RegistrationReference;
018    import com.liferay.portal.kernel.nio.intraband.welder.Welder;
019    import com.liferay.portal.kernel.process.ProcessExecutor;
020    import com.liferay.portal.kernel.resiliency.PortalResiliencyException;
021    import com.liferay.portal.kernel.resiliency.mpi.MPIHelperUtil;
022    import com.liferay.portal.kernel.resiliency.spi.SPI;
023    import com.liferay.portal.kernel.resiliency.spi.SPIConfiguration;
024    import com.liferay.portal.kernel.resiliency.spi.remote.RemoteSPI;
025    import com.liferay.portal.kernel.resiliency.spi.remote.RemoteSPIProxy;
026    import com.liferay.portal.kernel.util.StringBundler;
027    
028    import java.util.concurrent.Callable;
029    import java.util.concurrent.Future;
030    import java.util.concurrent.FutureTask;
031    import java.util.concurrent.SynchronousQueue;
032    import java.util.concurrent.TimeUnit;
033    
034    /**
035     * @author Shuyang Zhou
036     */
037    public abstract class BaseSPIProvider implements SPIProvider {
038    
039            public abstract RemoteSPI createRemoteSPI(SPIConfiguration spiConfiguration)
040                    throws PortalResiliencyException;
041    
042            @Override
043            public SPI createSPI(SPIConfiguration spiConfiguration)
044                    throws PortalResiliencyException {
045    
046                    String classPath = getClassPath();
047    
048                    RemoteSPI remoteSPI = createRemoteSPI(spiConfiguration);
049    
050                    String spiUUID = remoteSPI.getUUID();
051    
052                    SynchronousQueue<SPI> synchronousQueue =
053                            SPISynchronousQueueUtil.createSynchronousQueue(spiUUID);
054    
055                    FutureTask<RegistrationReference> weldServerFutureTask =
056                            new FutureTask<RegistrationReference>(
057                                    new WeldServerCallable(remoteSPI.getWelder()));
058    
059                    Thread weldServerThread = new Thread(
060                            weldServerFutureTask,
061                            "Weld Server Thread for " + spiConfiguration.getSPIId());
062    
063                    weldServerThread.setDaemon(true);
064    
065                    weldServerThread.start();
066    
067                    try {
068                            Future<SPI> cancelHandlerFuture = ProcessExecutor.execute(
069                                    spiConfiguration.getJavaExecutable(), classPath,
070                                    spiConfiguration.getJVMArguments(), remoteSPI);
071    
072                            SPI spi = synchronousQueue.poll(
073                                    spiConfiguration.getRegisterTimeout(), TimeUnit.MILLISECONDS);
074    
075                            if (spi != null) {
076                                    RegistrationReference registrationReference =
077                                            weldServerFutureTask.get(
078                                                    spiConfiguration.getRegisterTimeout(),
079                                                    TimeUnit.MILLISECONDS);
080    
081                                    RemoteSPIProxy remoteSPIProxy = new RemoteSPIProxy(
082                                            spi, spiConfiguration, getName(), cancelHandlerFuture,
083                                            registrationReference);
084    
085                                    if (!MPIHelperUtil.registerSPI(remoteSPIProxy)) {
086                                            cancelHandlerFuture.cancel(true);
087    
088                                            throw new PortalResiliencyException(
089                                                    "Unable to register SPI " + remoteSPIProxy +
090                                                            ". Forcibly cancelled SPI process launch.");
091                                    }
092    
093                                    return remoteSPIProxy;
094                            }
095    
096                            cancelHandlerFuture.cancel(true);
097    
098                            throw new PortalResiliencyException(
099                                    "SPI synchronous queue waiting timeout. Forcibly " +
100                                            "cancelled SPI process launch.");
101                    }
102                    catch (InterruptedException ie) {
103                            throw new PortalResiliencyException(
104                                    "Interrupted on waiting SPI process, registering back RMI stub",
105                                    ie);
106                    }
107                    catch (PortalResiliencyException pre) {
108                            throw pre;
109                    }
110                    catch (Exception e) {
111                            throw new PortalResiliencyException(
112                                    "Unable to launch SPI process", e);
113                    }
114                    finally {
115                            weldServerFutureTask.cancel(true);
116    
117                            SPISynchronousQueueUtil.destroySynchronousQueue(spiUUID);
118                    }
119            }
120    
121            public abstract String getClassPath();
122    
123            @Override
124            public String toString() {
125                    StringBundler sb = new StringBundler(5);
126    
127                    sb.append("{name=");
128                    sb.append(getName());
129                    sb.append(", classPath=");
130                    sb.append(getClassPath());
131                    sb.append("}");
132    
133                    return sb.toString();
134            }
135    
136            protected static class WeldServerCallable
137                    implements Callable<RegistrationReference> {
138    
139                    public WeldServerCallable(Welder welder) {
140                            _welder = welder;
141                    }
142    
143                    @Override
144                    public RegistrationReference call() throws Exception {
145                            return _welder.weld(MPIHelperUtil.getIntraband());
146                    }
147    
148                    private final Welder _welder;
149    
150            }
151    
152    }