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