001/*
002 * (C) Copyright 2006-2011 Nuxeo SA (http://nuxeo.com/) and others.
003 *
004 * Licensed under the Apache License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 *     http://www.apache.org/licenses/LICENSE-2.0
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 *
016 * Contributors:
017 *     Nuxeo - initial API and implementation
018 */
019
020package org.nuxeo.ecm.core.management.statuses;
021
022import static org.nuxeo.ecm.core.management.api.AdministrativeStatus.ACTIVE;
023import static org.nuxeo.ecm.core.management.api.AdministrativeStatus.PASSIVE;
024
025import java.util.Calendar;
026import java.util.List;
027import java.util.concurrent.Executors;
028import java.util.concurrent.ScheduledExecutorService;
029import java.util.concurrent.ThreadFactory;
030import java.util.concurrent.TimeUnit;
031
032import org.nuxeo.ecm.core.management.CoreManagementService;
033import org.nuxeo.ecm.core.management.api.AdministrativeStatus;
034import org.nuxeo.ecm.core.management.api.AdministrativeStatusManager;
035import org.nuxeo.ecm.core.management.api.GlobalAdministrativeStatusManager;
036import org.nuxeo.ecm.core.management.storage.AdministrativeStatusPersister;
037import org.nuxeo.runtime.transaction.TransactionHelper;
038
039/**
040 * Implementation class for the {@link AdministrativeStatusManager} service. For each Nuxeo Instance in the cluster one
041 * instance of this class is created.
042 *
043 * @author tiry
044 */
045public class AdministrativeStatusManagerImpl implements AdministrativeStatusManager, CoreManagementService {
046
047    protected final AdministrativeStatusPersister persister;
048
049    protected final GlobalAdministrativeStatusManager globalManager;
050
051    protected final String serverInstanceName;
052
053    protected final ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1, new ThreadFactory() {
054        @Override
055        public Thread newThread(Runnable r) {
056            return new Thread(r, "Nuxeo-Administrative-Statuses-Notify-Scheduler");
057        }
058    });
059
060    protected final Notifier[] notifiers = { new CoreEventNotifier(), new RuntimeEventNotifier() };
061
062    public AdministrativeStatusManagerImpl(GlobalAdministrativeStatusManager globalManager,
063            AdministrativeStatusPersister persister) {
064        this.globalManager = globalManager;
065        this.persister = persister;
066        serverInstanceName = NuxeoInstanceIdentifierHelper.getServerInstanceName();
067    }
068
069    public AdministrativeStatusManagerImpl(GlobalAdministrativeStatusManager globalManager,
070            AdministrativeStatusPersister persister, String instanceIdentifier) {
071        this.globalManager = globalManager;
072        this.persister = persister;
073        serverInstanceName = instanceIdentifier;
074    }
075
076    protected String getServerInstanceName() {
077        return serverInstanceName;
078    }
079
080    protected void notifyEvent(String eventName, String instanceIdentifier, String serviceIdentifier) {
081        for (Notifier notifier : notifiers) {
082            notifier.notifyEvent(eventName, instanceIdentifier, serviceIdentifier);
083        }
084    }
085
086    public void onNuxeoServerStartup() {
087
088        List<AdministrativeStatus> savedStatuses = persister.getAllStatuses(serverInstanceName);
089
090        // iterate throw declared services and init them if needed
091        List<AdministrableServiceDescriptor> descs = globalManager.listRegistredServices();
092
093        for (AdministrableServiceDescriptor desc : descs) {
094            boolean serviceExist = false;
095            for (AdministrativeStatus status : savedStatuses) {
096                if (desc.getId().equals(status.getServiceIdentifier())) {
097                    serviceExist = true;
098                    break;
099                }
100            }
101            if (!serviceExist) {
102                AdministrativeStatus newStatus = new AdministrativeStatus(desc.getInitialState(), "",
103                        Calendar.getInstance(), "system", serverInstanceName, desc.getId());
104                persister.saveStatus(newStatus);
105            }
106        }
107
108        doNotifyAllStatuses();
109
110        scheduler.scheduleAtFixedRate(new NotifyStatusesHandler(), 5, 5, TimeUnit.MINUTES);
111    }
112
113    protected void doNotifyAllStatuses() {
114        for (AdministrativeStatus status : persister.getAllStatuses(serverInstanceName)) {
115            notifyOnStatus(status);
116        }
117    }
118
119    public class NotifyStatusesHandler implements Runnable {
120        @Override
121        public void run() {
122            TransactionHelper.startTransaction();
123            boolean notified = false;
124            try {
125                doNotifyAllStatuses();
126                notified = true;
127            } finally {
128                if (!notified) {
129                    TransactionHelper.setTransactionRollbackOnly();
130                }
131                TransactionHelper.commitOrRollbackTransaction();
132            }
133        }
134    }
135
136    public void onNuxeoServerShutdown() {
137        scheduler.shutdown();
138    }
139
140    protected void notifyOnStatus(AdministrativeStatus status) {
141        if (status.isActive()) {
142            notifyEvent(ACTIVATED_EVENT, status.getInstanceIdentifier(), status.getServiceIdentifier());
143        } else if (status.isPassive()) {
144            notifyEvent(PASSIVATED_EVENT, status.getInstanceIdentifier(), status.getServiceIdentifier());
145        }
146    }
147
148    @Override
149    public AdministrativeStatus activateNuxeoInstance(String message, String login) {
150        return activate(GLOBAL_INSTANCE_AVAILABILITY, message, login);
151    }
152
153    @Override
154    public AdministrativeStatus deactivateNuxeoInstance(String message, String login) {
155        return deactivate(GLOBAL_INSTANCE_AVAILABILITY, message, login);
156    }
157
158    @Override
159    public AdministrativeStatus getNuxeoInstanceStatus() {
160        return getStatus(GLOBAL_INSTANCE_AVAILABILITY);
161    }
162
163    @Override
164    public AdministrativeStatus setNuxeoInstanceStatus(String state, String message, String login) {
165        return setStatus(GLOBAL_INSTANCE_AVAILABILITY, state, message, login);
166    }
167
168    @Override
169    public AdministrativeStatus activate(String serviceIdentifier, String message, String login) {
170        return setStatus(serviceIdentifier, ACTIVE, message, login);
171    }
172
173    @Override
174    public AdministrativeStatus deactivate(String serviceIdentifier, String message, String login) {
175        return setStatus(serviceIdentifier, PASSIVE, message, login);
176    }
177
178    @Override
179    public AdministrativeStatus setStatus(String serviceIdentifier, String state, String message, String login) {
180        AdministrativeStatus status = new AdministrativeStatus(state, message, Calendar.getInstance(), login,
181                serverInstanceName, serviceIdentifier);
182        status = persister.saveStatus(status);
183        notifyOnStatus(status);
184        return addLabelAndDescription(status);
185    }
186
187    @Override
188    public List<AdministrativeStatus> getAllStatuses() {
189        List<AdministrativeStatus> statuses = persister.getAllStatuses(serverInstanceName);
190        for (AdministrativeStatus status : statuses) {
191            addLabelAndDescription(status);
192        }
193        return statuses;
194    }
195
196    protected AdministrativeStatus addLabelAndDescription(AdministrativeStatus status) {
197        if (status == null) {
198            return null;
199        }
200        String id = status.getServiceIdentifier();
201        AdministrableServiceDescriptor desc = globalManager.getServiceDescriptor(id);
202        if (desc != null) {
203            status.setLabelAndDescription(desc.getLabel(), desc.getDescription());
204        }
205        return status;
206    }
207
208    @Override
209    public AdministrativeStatus getStatus(String serviceIdentifier) {
210        AdministrativeStatus status = persister.getStatus(serverInstanceName, serviceIdentifier);
211        addLabelAndDescription(status);
212        return status;
213    }
214
215}