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