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 ScheduledExecutorService scheduler;
054
055    protected final Notifier[] notifiers = { new CoreEventNotifier(), new RuntimeEventNotifier() };
056
057    public AdministrativeStatusManagerImpl(GlobalAdministrativeStatusManager globalManager,
058            AdministrativeStatusPersister persister) {
059        this.globalManager = globalManager;
060        this.persister = persister;
061        serverInstanceName = NuxeoInstanceIdentifierHelper.getServerInstanceName();
062    }
063
064    public AdministrativeStatusManagerImpl(GlobalAdministrativeStatusManager globalManager,
065            AdministrativeStatusPersister persister, String instanceIdentifier) {
066        this.globalManager = globalManager;
067        this.persister = persister;
068        serverInstanceName = instanceIdentifier;
069    }
070
071    protected String getServerInstanceName() {
072        return serverInstanceName;
073    }
074
075    protected void notifyEvent(String eventName, String instanceIdentifier, String serviceIdentifier) {
076        for (Notifier notifier : notifiers) {
077            notifier.notifyEvent(eventName, instanceIdentifier, serviceIdentifier);
078        }
079    }
080
081    public void onNuxeoServerStartup() {
082
083        List<AdministrativeStatus> savedStatuses = persister.getAllStatuses(serverInstanceName);
084
085        // iterate throw declared services and init them if needed
086        List<AdministrableServiceDescriptor> descs = globalManager.listRegistredServices();
087
088        for (AdministrableServiceDescriptor desc : descs) {
089            boolean serviceExist = false;
090            for (AdministrativeStatus status : savedStatuses) {
091                if (desc.getId().equals(status.getServiceIdentifier())) {
092                    serviceExist = true;
093                    break;
094                }
095            }
096            if (!serviceExist) {
097                AdministrativeStatus newStatus = new AdministrativeStatus(desc.getInitialState(), "",
098                        Calendar.getInstance(), "system", serverInstanceName, desc.getId());
099                persister.saveStatus(newStatus);
100            }
101        }
102
103        doNotifyAllStatuses();
104
105        scheduler = Executors.newScheduledThreadPool(1, new ThreadFactory() {
106            @Override
107            public Thread newThread(Runnable r) {
108                return new Thread(r, "Nuxeo-Administrative-Statuses-Notify-Scheduler");
109            }
110        });
111
112        scheduler.scheduleAtFixedRate(new NotifyStatusesHandler(), 5, 5, TimeUnit.MINUTES);
113    }
114
115    protected void doNotifyAllStatuses() {
116        for (AdministrativeStatus status : persister.getAllStatuses(serverInstanceName)) {
117            notifyOnStatus(status);
118        }
119    }
120
121    public class NotifyStatusesHandler implements Runnable {
122        @Override
123        public void run() {
124            TransactionHelper.startTransaction();
125            boolean notified = false;
126            try {
127                doNotifyAllStatuses();
128                notified = true;
129            } finally {
130                if (!notified) {
131                    TransactionHelper.setTransactionRollbackOnly();
132                }
133                TransactionHelper.commitOrRollbackTransaction();
134            }
135        }
136    }
137
138    public void onNuxeoServerShutdown() {
139        if (scheduler == null) {
140            return;
141        }
142        try {
143            scheduler.shutdown();
144        } finally {
145            scheduler = null;
146        }
147    }
148
149    protected void notifyOnStatus(AdministrativeStatus status) {
150        if (status.isActive()) {
151            notifyEvent(ACTIVATED_EVENT, status.getInstanceIdentifier(), status.getServiceIdentifier());
152        } else if (status.isPassive()) {
153            notifyEvent(PASSIVATED_EVENT, status.getInstanceIdentifier(), status.getServiceIdentifier());
154        }
155    }
156
157    @Override
158    public AdministrativeStatus activateNuxeoInstance(String message, String login) {
159        return activate(GLOBAL_INSTANCE_AVAILABILITY, message, login);
160    }
161
162    @Override
163    public AdministrativeStatus deactivateNuxeoInstance(String message, String login) {
164        return deactivate(GLOBAL_INSTANCE_AVAILABILITY, message, login);
165    }
166
167    @Override
168    public AdministrativeStatus getNuxeoInstanceStatus() {
169        return getStatus(GLOBAL_INSTANCE_AVAILABILITY);
170    }
171
172    @Override
173    public AdministrativeStatus setNuxeoInstanceStatus(String state, String message, String login) {
174        return setStatus(GLOBAL_INSTANCE_AVAILABILITY, state, message, login);
175    }
176
177    @Override
178    public AdministrativeStatus activate(String serviceIdentifier, String message, String login) {
179        return setStatus(serviceIdentifier, ACTIVE, message, login);
180    }
181
182    @Override
183    public AdministrativeStatus deactivate(String serviceIdentifier, String message, String login) {
184        return setStatus(serviceIdentifier, PASSIVE, message, login);
185    }
186
187    @Override
188    public AdministrativeStatus setStatus(String serviceIdentifier, String state, String message, String login) {
189        AdministrativeStatus status = new AdministrativeStatus(state, message, Calendar.getInstance(), login,
190                serverInstanceName, serviceIdentifier);
191        status = persister.saveStatus(status);
192        notifyOnStatus(status);
193        return addLabelAndDescription(status);
194    }
195
196    @Override
197    public List<AdministrativeStatus> getAllStatuses() {
198        List<AdministrativeStatus> statuses = persister.getAllStatuses(serverInstanceName);
199        for (AdministrativeStatus status : statuses) {
200            addLabelAndDescription(status);
201        }
202        return statuses;
203    }
204
205    protected AdministrativeStatus addLabelAndDescription(AdministrativeStatus status) {
206        if (status == null) {
207            return null;
208        }
209        String id = status.getServiceIdentifier();
210        AdministrableServiceDescriptor desc = globalManager.getServiceDescriptor(id);
211        if (desc != null) {
212            status.setLabelAndDescription(desc.getLabel(), desc.getDescription());
213        }
214        return status;
215    }
216
217    @Override
218    public AdministrativeStatus getStatus(String serviceIdentifier) {
219        AdministrativeStatus status = persister.getStatus(serverInstanceName, serviceIdentifier);
220        addLabelAndDescription(status);
221        return status;
222    }
223
224}