001/*
002 * Copyright (c) 2006-2011 Nuxeo SA (http://nuxeo.com/) and others.
003 *
004 * All rights reserved. This program and the accompanying materials
005 * are made available under the terms of the Eclipse Public License v1.0
006 * which accompanies this distribution, and is available at
007 * http://www.eclipse.org/legal/epl-v10.html
008 *
009 * Contributors:
010 *     mcedica
011 */
012package org.nuxeo.ecm.core.management.storage;
013
014import java.util.ArrayList;
015import java.util.Calendar;
016import java.util.List;
017
018import org.apache.commons.logging.Log;
019import org.apache.commons.logging.LogFactory;
020import org.nuxeo.ecm.core.api.DocumentModel;
021import org.nuxeo.ecm.core.api.DocumentModelList;
022import org.nuxeo.ecm.core.api.DocumentRef;
023import org.nuxeo.ecm.core.api.PathRef;
024import org.nuxeo.ecm.core.management.api.AdministrativeStatus;
025import org.nuxeo.runtime.api.Framework;
026import org.nuxeo.runtime.osgi.OSGiRuntimeService;
027
028/**
029 * Used to control the server administrative status: the status of the server can be passive or active.
030 *
031 * @author Mariana Cedica
032 */
033public class DocumentModelStatusPersister implements AdministrativeStatusPersister {
034
035    public static final String ADMINISTRATIVE_INFO_CONTAINER = "administrative-infos";
036
037    public static final String ADMINISTRATIVE_INFO_CONTAINER_DOCUMENT_TYPE = "AdministrativeStatusContainer";
038
039    public static final String ADMINISTRATIVE_STATUS_DOCUMENT_TYPE = "AdministrativeStatus";
040
041    public static final String STATUS_PROPERTY = "status:administrative_status";
042
043    public static final String MESSAGE_PROPERTY = "status:statusMessage";
044
045    public static final String INSTANCE_PROPERTY = "status:instanceId";
046
047    public static final String SERVICE_PROPERTY = "status:serviceId";
048
049    public static final String LOGIN_PROPERTY = "status:userLogin";
050
051    private static final Log log = LogFactory.getLog(DocumentModelStatusPersister.class);
052
053    private class StatusSaver extends DocumentStoreSessionRunner {
054
055        protected final AdministrativeStatus status;
056
057        private StatusSaver(AdministrativeStatus status) {
058            this.status = status;
059        }
060
061        @Override
062        protected String errorMessage() {
063            return "Cannot save  " + status;
064        }
065
066        @Override
067        public void run() {
068            doGetOrCreateDoc(status);
069            session.save();
070        }
071
072        public AdministrativeStatus getStatus() {
073            return status;
074        }
075
076        protected DocumentModel doGetOrCreateContainer() {
077
078            DocumentRef admRootDocRef = DocumentStoreManager.newPath(ADMINISTRATIVE_INFO_CONTAINER);
079
080            if (!session.exists(admRootDocRef)) {
081                DocumentModel doc = session.createDocumentModel(DocumentStoreManager.newPath().toString(),
082                        ADMINISTRATIVE_INFO_CONTAINER, ADMINISTRATIVE_INFO_CONTAINER_DOCUMENT_TYPE);
083                doc.setPropertyValue("dc:title", ADMINISTRATIVE_INFO_CONTAINER);
084                doc = session.createDocument(doc);
085                session.save();
086            }
087
088            return session.getDocument(admRootDocRef);
089        }
090
091        protected DocumentModel doGetOrCreateDoc(AdministrativeStatus status) {
092            DocumentModel administrativeContainer = doGetOrCreateContainer();
093
094            DocumentRef statusDocRef = new PathRef(administrativeContainer.getPathAsString() + "/"
095                    + getAdministrativeStatusDocName(status));
096
097            DocumentModel doc;
098            boolean create = false;
099            if (!session.exists(statusDocRef)) {
100                create = true;
101                doc = session.createDocumentModel(administrativeContainer.getPathAsString(),
102                        getAdministrativeStatusDocName(status), ADMINISTRATIVE_STATUS_DOCUMENT_TYPE);
103            } else {
104                doc = session.getDocument(statusDocRef);
105            }
106
107            doc.setPropertyValue(LOGIN_PROPERTY, status.getUserLogin());
108            doc.setPropertyValue(INSTANCE_PROPERTY, status.getInstanceIdentifier());
109            doc.setPropertyValue(SERVICE_PROPERTY, status.getServiceIdentifier());
110            doc.setPropertyValue(MESSAGE_PROPERTY, status.getMessage());
111            doc.setPropertyValue(STATUS_PROPERTY, status.getState());
112
113            doc.setPropertyValue("dc:title", getAdministrativeStatusDocName(status));
114
115            if (create) {
116                doc = session.createDocument(doc);
117            } else {
118                doc = session.saveDocument(doc);
119            }
120            session.save();
121
122            return doc;
123        }
124
125    }
126
127    protected String getAdministrativeStatusDocName(AdministrativeStatus status) {
128        return status.getInstanceIdentifier() + "--" + status.getServiceIdentifier();
129    }
130
131    public static class StatusFetcher extends DocumentStoreSessionRunner {
132
133        protected final String instanceId;
134
135        protected final String serviceId;
136
137        protected final List<String> allInstanceIds = new ArrayList<String>();
138
139        protected final List<AdministrativeStatus> statuses = new ArrayList<AdministrativeStatus>();
140
141        public StatusFetcher(String instanceId, String serviceId) {
142            this.instanceId = instanceId;
143            this.serviceId = serviceId;
144        }
145
146        @Override
147        protected String errorMessage() {
148            StringBuilder sb = new StringBuilder();
149            sb.append("Cannot fetch statuses ");
150            if (instanceId != null) {
151                sb.append(" for ").append(instanceId);
152            }
153            if (serviceId != null) {
154                sb.append(":").append(serviceId);
155            }
156            return sb.toString();
157        }
158
159        @Override
160        public void run() {
161            StringBuilder sb = new StringBuilder("select * from ");
162            sb.append(ADMINISTRATIVE_STATUS_DOCUMENT_TYPE);
163
164            boolean onlyFetchIds = false;
165            if (instanceId == null) {
166                onlyFetchIds = true;
167            } else {
168                sb.append(" where ");
169                sb.append(INSTANCE_PROPERTY);
170                sb.append("='");
171                sb.append(instanceId);
172                sb.append("'");
173                if (serviceId != null) {
174                    sb.append(" AND ");
175                    sb.append(SERVICE_PROPERTY);
176                    sb.append("='");
177                    sb.append(serviceId);
178                    sb.append("'");
179                }
180            }
181
182            DocumentModelList result = session.query(sb.toString());
183
184            for (DocumentModel doc : result) {
185                if (onlyFetchIds) {
186                    String id = (String) doc.getPropertyValue(INSTANCE_PROPERTY);
187                    if (!allInstanceIds.contains(id)) {
188                        allInstanceIds.add(id);
189                    }
190                } else {
191                    statuses.add(wrap(doc));
192                }
193            }
194        }
195
196        protected AdministrativeStatus wrap(DocumentModel doc) {
197
198            String userLogin = (String) doc.getPropertyValue(LOGIN_PROPERTY);
199            String id = (String) doc.getPropertyValue(INSTANCE_PROPERTY);
200            String service = (String) doc.getPropertyValue(SERVICE_PROPERTY);
201            String message = (String) doc.getPropertyValue(MESSAGE_PROPERTY);
202            String state = (String) doc.getPropertyValue(STATUS_PROPERTY);
203            Calendar modified = (Calendar) doc.getPropertyValue("dc:modified");
204
205            return new AdministrativeStatus(state, message, modified, userLogin, id, service);
206        }
207    }
208
209    @Override
210    public List<String> getAllInstanceIds() {
211        StatusFetcher fetcher = new StatusFetcher(null, null);
212        fetcher.runUnrestricted();
213        return fetcher.allInstanceIds;
214    }
215
216    @Override
217    public List<AdministrativeStatus> getAllStatuses(String instanceId) {
218        StatusFetcher fetcher = new StatusFetcher(instanceId, null);
219        fetcher.runUnrestricted();
220        return fetcher.statuses;
221    }
222
223    @Override
224    public AdministrativeStatus getStatus(String instanceId, String serviceIdentifier) {
225        StatusFetcher fetcher = new StatusFetcher(instanceId, serviceIdentifier);
226        fetcher.runUnrestricted();
227        if (fetcher.statuses.size() == 1) {
228            return fetcher.statuses.get(0);
229        } else {
230            log.warn("Unable to fetch status for service " + serviceIdentifier + " in instance " + instanceId);
231            return null;
232        }
233    }
234
235    @Override
236    public void remove(String instanceId) {
237        throw new UnsupportedOperationException("Not implemented for now");
238    }
239
240    @Override
241    public AdministrativeStatus saveStatus(AdministrativeStatus status) {
242        StatusSaver saver = new StatusSaver(status);
243        saver.runUnrestricted();
244        return saver.getStatus();
245    }
246
247}