001    /**
002     * Copyright (c) 2010 Yahoo! Inc. All rights reserved.
003     * Licensed under the Apache License, Version 2.0 (the "License");
004     * you may not use this file except in compliance with the License.
005     * You may obtain a copy of the License at
006     *
007     *   http://www.apache.org/licenses/LICENSE-2.0
008     *
009     *  Unless required by applicable law or agreed to in writing, software
010     *  distributed under the License is distributed on an "AS IS" BASIS,
011     *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
012     *  See the License for the specific language governing permissions and
013     *  limitations under the License. See accompanying LICENSE file.
014     */
015    package org.apache.oozie.service;
016    
017    import org.apache.hadoop.conf.Configuration;
018    import org.apache.oozie.ErrorCode;
019    import org.apache.oozie.service.Service;
020    import org.apache.oozie.service.ServiceException;
021    import org.apache.oozie.service.Services;
022    import org.apache.oozie.util.IOUtils;
023    import org.xml.sax.SAXException;
024    
025    import javax.xml.XMLConstants;
026    import javax.xml.transform.stream.StreamSource;
027    import javax.xml.validation.Schema;
028    import javax.xml.validation.SchemaFactory;
029    import java.io.IOException;
030    import java.util.ArrayList;
031    import java.util.List;
032    
033    /**
034     * Service that loads Oozie workflow definition schema and registered extension schemas.
035     */
036    public class SchemaService implements Service {
037    
038        public static final String CONF_PREFIX = Service.CONF_PREFIX + "SchemaService.";
039    
040        public static final String WF_CONF_EXT_SCHEMAS = CONF_PREFIX + "wf.ext.schemas";
041    
042        public static final String COORD_CONF_EXT_SCHEMAS = CONF_PREFIX + "coord.ext.schemas";
043    
044        public static final String SLA_CONF_EXT_SCHEMAS = CONF_PREFIX + "sla.ext.schemas";
045    
046        public static final String SLA_NAME_SPACE_URI = "uri:oozie:sla:0.1";
047    
048        private Schema wfSchema;
049    
050        private Schema coordSchema;
051    
052        private Schema slaSchema;
053    
054        private static final String OOZIE_WORKFLOW_XSD[] = {"oozie-workflow-0.1.xsd", "oozie-workflow-0.2.xsd"};
055        private static final String OOZIE_COORDINATOR_XSD[] = {"oozie-coordinator-0.1.xsd"};
056        private static final String OOZIE_SLA_SEMANTIC_XSD[] = {"gms-oozie-sla-0.1.xsd"};
057    
058        private Schema loadSchema(Configuration conf, String[] baseSchemas, String extSchema) throws SAXException,
059                IOException {
060            List<StreamSource> sources = new ArrayList<StreamSource>();
061            for (String baseSchema : baseSchemas) {
062                sources.add(new StreamSource(IOUtils.getResourceAsStream(baseSchema, -1)));
063            }
064            String[] schemas = conf.getStrings(extSchema);
065            if (schemas != null) {
066                for (String schema : schemas) {
067                    schema = schema.replace("\n", "").trim();
068                    if (schema.length() > 0) {
069                        sources.add(new StreamSource(IOUtils.getResourceAsStream(schema, -1)));
070                    }
071                }
072            }
073            SchemaFactory factory = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
074            return factory.newSchema(sources.toArray(new StreamSource[sources.size()]));
075        }
076    
077        /**
078         * Initialize the service.
079         *
080         * @param services services instance.
081         * @throws ServiceException thrown if the service could not be initialized.
082         */
083        public void init(Services services) throws ServiceException {
084            try {
085                wfSchema = loadSchema(services.getConf(), OOZIE_WORKFLOW_XSD, WF_CONF_EXT_SCHEMAS);
086                coordSchema = loadSchema(services.getConf(), OOZIE_COORDINATOR_XSD, COORD_CONF_EXT_SCHEMAS);
087                slaSchema = loadSchema(services.getConf(), OOZIE_SLA_SEMANTIC_XSD, SLA_CONF_EXT_SCHEMAS);
088            }
089            catch (SAXException ex) {
090                throw new ServiceException(ErrorCode.E0130, ex.getMessage(), ex);
091            }
092            catch (IOException ex) {
093                throw new ServiceException(ErrorCode.E0131, ex.getMessage(), ex);
094            }
095        }
096    
097        /**
098         * Return the public interface of the service.
099         *
100         * @return {@link SchemaService}.
101         */
102        public Class<? extends Service> getInterface() {
103            return SchemaService.class;
104        }
105    
106        /**
107         * Destroy the service.
108         */
109        public void destroy() {
110            wfSchema = null;
111        }
112    
113        /**
114         * Return the schema for XML validation of application definitions.
115         *
116         * @param schemaName: Name of schema definition (i.e. WORKFLOW/COORDINATOR)
117         * @return the schema for XML validation of application definitions.
118         */
119        public Schema getSchema(SchemaName schemaName) {
120            if (schemaName == SchemaName.WORKFLOW) {
121                return wfSchema;
122            }
123            else {
124                if (schemaName == SchemaName.COORDINATOR) {
125                    return coordSchema;
126                }
127                else {
128                    if (schemaName == SchemaName.SLA_ORIGINAL) {
129                        return slaSchema;
130                    }
131                    else {
132                        throw new RuntimeException("No schema found with name " + schemaName);
133                    }
134                }
135            }
136        }
137    
138        public enum SchemaName {
139            WORKFLOW(1), COORDINATOR(2), SLA_ORIGINAL(3);
140            private int id;
141    
142            private SchemaName(int id) {
143                this.id = id;
144            }
145    
146            public int getId() {
147                return id;
148            }
149        }
150    }