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