/* * * * Copyright 2014 Orient Technologies LTD (info(at)orientechnologies.com) * * * * Licensed under the Apache License, Version 2.0 (the "License"); * * you may not use this file except in compliance with the License. * * You may obtain a copy of the License at * * * * http://www.apache.org/licenses/LICENSE-2.0 * * * * Unless required by applicable law or agreed to in writing, software * * distributed under the License is distributed on an "AS IS" BASIS, * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * * See the License for the specific language governing permissions and * * limitations under the License. * * * * For more information: http://www.orientechnologies.com * */ package com.orientechnologies.orient.core.metadata.function; import com.orientechnologies.common.exception.OException; import com.orientechnologies.common.util.OCallable; import com.orientechnologies.orient.core.command.OCommandManager; import com.orientechnologies.orient.core.command.script.OCommandExecutorFunction; import com.orientechnologies.orient.core.command.script.OCommandFunction; import com.orientechnologies.orient.core.db.ODatabaseRecordThreadLocal; import com.orientechnologies.orient.core.db.document.ODatabaseDocument; import com.orientechnologies.orient.core.metadata.OMetadataInternal; import com.orientechnologies.orient.core.metadata.schema.OClass; import com.orientechnologies.orient.core.metadata.schema.OProperty; import com.orientechnologies.orient.core.metadata.schema.OType; import com.orientechnologies.orient.core.record.impl.ODocument; import com.orientechnologies.orient.core.sql.query.OSQLSynchQuery; import com.orientechnologies.orient.core.storage.ORecordDuplicatedException; import java.util.*; import java.util.concurrent.ConcurrentHashMap; /** * Manages stored functions. * * @author Luca Garulli */ public class OFunctionLibraryImpl implements OFunctionLibrary { protected Map<String, OFunction> functions = new ConcurrentHashMap<String, OFunction>(); static { OCommandManager.instance().registerExecutor(OCommandFunction.class, OCommandExecutorFunction.class); } public OFunctionLibraryImpl() { } public void create() { init(); } public void load() { // COPY CALLBACK IN RAM final Map<String, OCallable<Object, Map<Object, Object>>> callbacks = new HashMap<String, OCallable<Object, Map<Object, Object>>>(); for (Map.Entry<String, OFunction> entry : functions.entrySet()) { if (entry.getValue().getCallback() != null) callbacks.put(entry.getKey(), entry.getValue().getCallback()); } functions.clear(); // LOAD ALL THE FUNCTIONS IN MEMORY final ODatabaseDocument db = ODatabaseRecordThreadLocal.INSTANCE.get(); if (((OMetadataInternal) db.getMetadata()).getImmutableSchemaSnapshot().existsClass("OFunction")) { List<ODocument> result = db.query(new OSQLSynchQuery<ODocument>("select from OFunction order by name")); for (ODocument d : result) { d.reload(); //skip the function records which do not contain real data if (d.fields() == 0) continue; final OFunction f = new OFunction(d); // RESTORE CALLBACK IF ANY f.setCallback(callbacks.get(f.getName())); functions.put(d.field("name").toString().toUpperCase(), f); } } } public Set<String> getFunctionNames() { return Collections.unmodifiableSet(functions.keySet()); } public OFunction getFunction(final String iName) { return functions.get(iName.toUpperCase()); } public synchronized OFunction createFunction(final String iName) { init(); final OFunction f = new OFunction().setName(iName); try { f.save(); } catch (ORecordDuplicatedException ex) { throw OException.wrapException(new OFunctionDuplicatedException("Function with name '" + iName + "' already exist"), null); } functions.put(iName.toUpperCase(), f); return f; } public void close() { functions.clear(); } protected void init() { final ODatabaseDocument db = ODatabaseRecordThreadLocal.INSTANCE.get(); if (db.getMetadata().getSchema().existsClass("OFunction")) { final OClass f = db.getMetadata().getSchema().getClass("OFunction"); OProperty prop = f.getProperty("name"); if (prop.getAllIndexes().isEmpty()) prop.createIndex(OClass.INDEX_TYPE.UNIQUE_HASH_INDEX); return; } final OClass f = db.getMetadata().getSchema().createClass("OFunction"); OProperty prop = f.createProperty("name", OType.STRING, (OType) null, true); prop.set(OProperty.ATTRIBUTES.NOTNULL, true); prop.set(OProperty.ATTRIBUTES.MANDATORY, true); prop.createIndex(OClass.INDEX_TYPE.UNIQUE_HASH_INDEX); f.createProperty("code", OType.STRING, (OType) null, true); f.createProperty("language", OType.STRING, (OType) null, true); f.createProperty("idempotent", OType.BOOLEAN, (OType) null, true); f.createProperty("parameters", OType.EMBEDDEDLIST, OType.STRING, true); } @Override public synchronized void dropFunction(OFunction function) { String name = function.getName(); ODocument doc = function.getDocument(); doc.delete(); functions.remove(name.toUpperCase()); } @Override public synchronized void dropFunction(String iName) { OFunction function = getFunction(iName); ODocument doc = function.getDocument(); doc.delete(); functions.remove(iName.toUpperCase()); } }