001/**
002 * Licensed to the Apache Software Foundation (ASF) under one
003 * or more contributor license agreements.  See the NOTICE file
004 * distributed with this work for additional information
005 * regarding copyright ownership.  The ASF licenses this file
006 * to you under the Apache License, Version 2.0 (the
007 * "License"); you may not use this file except in compliance
008 * with the License.  You may obtain a copy of the License at
009 *
010 *      http://www.apache.org/licenses/LICENSE-2.0
011 *
012 * Unless required by applicable law or agreed to in writing, software
013 * distributed under the License is distributed on an "AS IS" BASIS,
014 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
015 * See the License for the specific language governing permissions and
016 * limitations under the License.
017 */
018
019package org.apache.oozie.service;
020
021import java.io.IOException;
022import java.util.ArrayList;
023import java.util.HashSet;
024import java.util.List;
025import java.util.Set;
026
027import javax.xml.XMLConstants;
028import javax.xml.transform.stream.StreamSource;
029import javax.xml.validation.Schema;
030import javax.xml.validation.SchemaFactory;
031
032import org.apache.oozie.ErrorCode;
033import org.apache.oozie.util.IOUtils;
034import org.apache.oozie.util.schema.ResourceResolver;
035import org.xml.sax.SAXException;
036
037
038/**
039 * Service that loads Oozie workflow definition schema and registered extension
040 * schemas.
041 */
042
043public class SchemaService implements Service {
044
045    public static final String CONF_PREFIX = Service.CONF_PREFIX + "SchemaService.";
046
047    public static final String WF_CONF_SCHEMAS = CONF_PREFIX + "wf.schemas";
048
049    public static final String WF_CONF_EXT_SCHEMAS = CONF_PREFIX + "wf.ext.schemas";
050
051    public static final String COORD_CONF_SCHEMAS = CONF_PREFIX + "coord.schemas";
052
053    public static final String COORD_CONF_EXT_SCHEMAS = CONF_PREFIX + "coord.ext.schemas";
054
055    public static final String BUNDLE_CONF_SCHEMAS = CONF_PREFIX + "bundle.schemas";
056
057    public static final String BUNDLE_CONF_EXT_SCHEMAS = CONF_PREFIX + "bundle.ext.schemas";
058
059    public static final String SLA_CONF_SCHEMAS = CONF_PREFIX + "sla.schemas";
060
061    public static final String SLA_CONF_EXT_SCHEMAS = CONF_PREFIX + "sla.ext.schemas";
062
063    @Deprecated
064    public static final String SLA_NAME_SPACE_URI = "uri:oozie:sla:0.1";
065
066    public static final String SLA_NAMESPACE_URI_2 = "uri:oozie:sla:0.2";
067
068    public static final String COORDINATOR_NAMESPACE_URI_1 = "uri:oozie:coordinator:0.1";
069
070    private Schema wfSchema;
071
072    private Schema coordSchema;
073
074    private Schema bundleSchema;
075
076    private Schema slaSchema;
077
078    private Schema loadSchema(String baseSchemas, String extSchema) throws SAXException, IOException {
079        Set<String> schemaNames = new HashSet<String>();
080        String[] schemas = ConfigurationService.getStrings(baseSchemas);
081        if (schemas != null) {
082            for (String schema : schemas) {
083                schema = schema.trim();
084                if (!schema.isEmpty()) {
085                    schemaNames.add(schema);
086                }
087            }
088        }
089        schemas = ConfigurationService.getStrings(extSchema);
090        if (schemas != null) {
091            for (String schema : schemas) {
092                schema = schema.trim();
093                if (!schema.isEmpty()) {
094                    schemaNames.add(schema);
095                }
096            }
097        }
098        List<StreamSource> sources = new ArrayList<StreamSource>();
099        for (String schemaName : schemaNames) {
100            StreamSource s = new StreamSource(IOUtils.getResourceAsStream(schemaName, -1));
101            s.setSystemId(schemaName);
102            sources.add(s);
103        }
104        SchemaFactory factory = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
105        factory.setResourceResolver(new ResourceResolver());
106        return factory.newSchema(sources.toArray(new StreamSource[sources.size()]));
107    }
108
109    /**
110     * Initialize the service.
111     *
112     * @param services services instance.
113     * @throws ServiceException thrown if the service could not be initialized.
114     */
115    @Override
116    public void init(Services services) throws ServiceException {
117        try {
118            wfSchema = loadSchema(WF_CONF_SCHEMAS, WF_CONF_EXT_SCHEMAS);
119            coordSchema = loadSchema(COORD_CONF_SCHEMAS, COORD_CONF_EXT_SCHEMAS);
120            bundleSchema = loadSchema(BUNDLE_CONF_SCHEMAS, BUNDLE_CONF_EXT_SCHEMAS);
121            slaSchema = loadSchema(SLA_CONF_SCHEMAS, SLA_CONF_EXT_SCHEMAS);
122        }
123        catch (SAXException ex) {
124            throw new ServiceException(ErrorCode.E0130, ex.getMessage(), ex);
125        }
126        catch (IOException ex) {
127            throw new ServiceException(ErrorCode.E0131, ex.getMessage(), ex);
128        }
129    }
130
131    /**
132     * Return the public interface of the service.
133     *
134     * @return {@link SchemaService}.
135     */
136    @Override
137    public Class<? extends Service> getInterface() {
138        return SchemaService.class;
139    }
140
141    /**
142     * Destroy the service.
143     */
144    @Override
145    public void destroy() {
146        wfSchema = null;
147        bundleSchema = null;
148        slaSchema = null;
149        coordSchema = null;
150    }
151
152    /**
153     * Return the schema for XML validation of application definitions.
154     *
155     * @param schemaName Name of schema definition (i.e.
156     *        WORKFLOW/COORDINATOR/BUNDLE)
157     * @return the schema for XML validation of application definitions.
158     */
159    public Schema getSchema(SchemaName schemaName) {
160        Schema returnSchema = null;
161        if (schemaName == SchemaName.WORKFLOW) {
162            returnSchema = wfSchema;
163        }
164        else if (schemaName == SchemaName.COORDINATOR) {
165            returnSchema = coordSchema;
166        }
167        else if (schemaName == SchemaName.BUNDLE) {
168            returnSchema = bundleSchema;
169        }
170        else if (schemaName == SchemaName.SLA_ORIGINAL) {
171            returnSchema = slaSchema;
172        }
173        else {
174            throw new RuntimeException("No schema found with name " + schemaName);
175        }
176        return returnSchema;
177    }
178
179    public enum SchemaName {
180        WORKFLOW(1), COORDINATOR(2), SLA_ORIGINAL(3), BUNDLE(4);
181        private final int id;
182
183        private SchemaName(int id) {
184            this.id = id;
185        }
186
187        public int getId() {
188            return id;
189        }
190    }
191}