public static FileMetadata detectFromFile(File file) throws Exception

package com.thinkbiganalytics.kylo.metadata.file.service;

import com.thinkbiganalytics.kylo.metadata.file.FileMetadata;
import com.thinkbiganalytics.kylo.tika.detector.CSVDetector;
import com.thinkbiganalytics.kylo.tika.detector.InputStreamUtil;
import org.apache.commons.io.FileUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.tika.Tika;
import org.apache.tika.config.TikaConfig;
import org.apache.tika.detect.AutoDetectReader;
import org.apache.tika.detect.XmlRootExtractor;
import org.apache.tika.io.TikaInputStream;
import org.apache.tika.metadata.Metadata;
import org.apache.tika.mime.MediaType;
import java.io.File;
import java.io.InputStream;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.util.HashMap;
import java.util.Map;
import javax.xml.namespace.QName;

/**
 * Detect file metadata using Apache Tika
 */
public class FileMetadataService {

    static int bytesToTest = 512000;

    /**
     * Detect file format and metadata/mimetype from the incoming input sream
     *
     * @param is       the file input stream
     * @param fileName the name of the file (optional)
     * @return the metadata object
     */
    public static FileMetadata detectFromStream(InputStream is, String fileName) throws Exception {
        Tika tika = new Tika();
        TikaConfig tikaConfig = new TikaConfig();
        Metadata md = new Metadata();
        md.set(Metadata.RESOURCE_NAME_KEY, fileName);
        Charset charset = StandardCharsets.ISO_8859_1;
        byte[] header = InputStreamUtil.readHeader(is, bytesToTest);
        AutoDetectReader reader = new AutoDetectReader(InputStreamUtil.asStream(header));
        charset = reader.getCharset();
        MediaType mediaType = null;
        if (fileName != null && fileName.endsWith(".csv")) {
            mediaType = detectCsv(InputStreamUtil.asStream(header), md);
        } else {
            mediaType = tika.getDetector().detect(TikaInputStream.get(InputStreamUtil.asStream(header)), md);
            // manually call the csv detector if it is a text file that is not matched.
            // this is needed, and cannot be added to the /META-INF/services/org.apache.tika.detect.Detector file since there is no guarantee of order
            // we first want to detect the type from the core tika mimetypes.
            // then if we didnt get a concrete type attempt to parse it via csv
            if (mediaType.equals(MediaType.TEXT_PLAIN)) {
                mediaType = detectCsv(InputStreamUtil.asStream(header), md);
            } else if (mediaType.equals(MediaType.APPLICATION_XML)) {
                XmlRootExtractor rowTagExtractor = new XmlRootExtractor();
                QName root = rowTagExtractor.extractRootElement(InputStreamUtil.asStream(header));
                if (root != null) {
                    String rowTag = root.getLocalPart();
                    md.set("rowTag", rowTag);
                } else {
                    // unable to detect RowTag from XML!!
                }
            }
        }
        if (mediaType == null) {
            mediaType = MediaType.OCTET_STREAM;
        }
        FileMetadata fileMetadata = new FileMetadata(mediaType.toString());
        fileMetadata.addProperties(metadataToMap(md));
        fileMetadata.setSubType(mediaType.getSubtype());
        String encoding = charset.name();
        fileMetadata.setEncoding(StringUtils.isBlank(encoding) ? StandardCharsets.UTF_8.name() : encoding);
        return fileMetadata;
    }

    private static MediaType detectCsv(InputStream inputStream, Metadata md) throws Exception {
        CSVDetector d = new CSVDetector();
        return d.detect(inputStream, md);
    }

    private static Map<String, String> metadataToMap(Metadata metadata) {
        Map<String, String> map = new HashMap<>();
        for (String name : metadata.names()) {
            String firstValue = metadata.get(name);
            map.put(name, firstValue);
        }
        return map;
    }

    /**
     * Detect metadata for a specific file
     *
     * @param file the file to inspect
     * @return the metadata for that file
     */

{
        InputStream inputStream = FileUtils.openInputStream(file);
        return detectFromStream(inputStream, file.getName());
    }
}


{
        Map<String, String> map = new HashMap<>();
        for (String name : metadata.names()) {
            String firstValue = metadata.get(name);
            map.put(name, firstValue);
        }
        return map;
    }

package com.thinkbiganalytics.kylo.metadata.file.service;

import com.thinkbiganalytics.kylo.metadata.file.FileMetadata;
import com.thinkbiganalytics.kylo.tika.detector.CSVDetector;
import com.thinkbiganalytics.kylo.tika.detector.InputStreamUtil;
import org.apache.commons.io.FileUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.tika.Tika;
import org.apache.tika.config.TikaConfig;
import org.apache.tika.detect.AutoDetectReader;
import org.apache.tika.detect.XmlRootExtractor;
import org.apache.tika.io.TikaInputStream;
import org.apache.tika.metadata.Metadata;
import org.apache.tika.mime.MediaType;
import java.io.File;
import java.io.InputStream;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.util.HashMap;
import java.util.Map;
import javax.xml.namespace.QName;

/**
 * Detect file metadata using Apache Tika
 */
public class FileMetadataService {

    static int bytesToTest = 512000;

    /**
     * Detect file format and metadata/mimetype from the incoming input sream
     *
     * @param is       the file input stream
     * @param fileName the name of the file (optional)
     * @return the metadata object
     */
    public static FileMetadata detectFromStream(InputStream is, String fileName) throws Exception {
        Tika tika = new Tika();
        TikaConfig tikaConfig = new TikaConfig();
        Metadata md = new Metadata();
        md.set(Metadata.RESOURCE_NAME_KEY, fileName);
        Charset charset = StandardCharsets.ISO_8859_1;
        byte[] header = InputStreamUtil.readHeader(is, bytesToTest);
        AutoDetectReader reader = new AutoDetectReader(InputStreamUtil.asStream(header));
        charset = reader.getCharset();
        MediaType mediaType = null;
        if (fileName != null && fileName.endsWith(".csv")) {
            mediaType = detectCsv(InputStreamUtil.asStream(header), md);
        } else {
            mediaType = tika.getDetector().detect(TikaInputStream.get(InputStreamUtil.asStream(header)), md);
            // manually call the csv detector if it is a text file that is not matched.
            // this is needed, and cannot be added to the /META-INF/services/org.apache.tika.detect.Detector file since there is no guarantee of order
            // we first want to detect the type from the core tika mimetypes.
            // then if we didnt get a concrete type attempt to parse it via csv
            if (mediaType.equals(MediaType.TEXT_PLAIN)) {
                mediaType = detectCsv(InputStreamUtil.asStream(header), md);
            } else if (mediaType.equals(MediaType.APPLICATION_XML)) {
                XmlRootExtractor rowTagExtractor = new XmlRootExtractor();
                QName root = rowTagExtractor.extractRootElement(InputStreamUtil.asStream(header));
                if (root != null) {
                    String rowTag = root.getLocalPart();
                    md.set("rowTag", rowTag);
                } else {
                    // unable to detect RowTag from XML!!
                }
            }
        }
        if (mediaType == null) {
            mediaType = MediaType.OCTET_STREAM;
        }
        FileMetadata fileMetadata = new FileMetadata(mediaType.toString());
        fileMetadata.addProperties(metadataToMap(md));
        fileMetadata.setSubType(mediaType.getSubtype());
        String encoding = charset.name();
        fileMetadata.setEncoding(StringUtils.isBlank(encoding) ? StandardCharsets.UTF_8.name() : encoding);
        return fileMetadata;
    }

    private static MediaType detectCsv(InputStream inputStream, Metadata md) throws Exception {
        CSVDetector d = new CSVDetector();
        return d.detect(inputStream, md);
    }

    private static Map<String, String> metadataToMap(Metadata metadata)

    /**
     * Detect metadata for a specific file
     *
     * @param file the file to inspect
     * @return the metadata for that file
     */
    public static FileMetadata detectFromFile(File file) throws Exception {
        InputStream inputStream = FileUtils.openInputStream(file);
        return detectFromStream(inputStream, file.getName());
    }
}


package com.thinkbiganalytics.kylo.metadata.file.service;

import com.thinkbiganalytics.kylo.metadata.file.FileMetadata;
import com.thinkbiganalytics.kylo.tika.detector.CSVDetector;
import com.thinkbiganalytics.kylo.tika.detector.InputStreamUtil;
import org.apache.commons.io.FileUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.tika.Tika;
import org.apache.tika.config.TikaConfig;
import org.apache.tika.detect.AutoDetectReader;
import org.apache.tika.detect.XmlRootExtractor;
import org.apache.tika.io.TikaInputStream;
import org.apache.tika.metadata.Metadata;
import org.apache.tika.mime.MediaType;
import java.io.File;
import java.io.InputStream;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.util.HashMap;
import java.util.Map;
import javax.xml.namespace.QName;

/**
 * Detect file metadata using Apache Tika
 */
public class FileMetadataService {

    static int bytesToTest = 512000;

    /**
     * Detect file format and metadata/mimetype from the incoming input sream
     *
     * @param is       the file input stream
     * @param fileName the name of the file (optional)
     * @return the metadata object
     */
    public static FileMetadata detectFromStream(InputStream is, String fileName) throws Exception {
        Tika tika = new Tika();
        TikaConfig tikaConfig = new TikaConfig();
        Metadata md = new Metadata();
        md.set(Metadata.RESOURCE_NAME_KEY, fileName);
        Charset charset = StandardCharsets.ISO_8859_1;
        byte[] header = InputStreamUtil.readHeader(is, bytesToTest);
        AutoDetectReader reader = new AutoDetectReader(InputStreamUtil.asStream(header));
        charset = reader.getCharset();
        MediaType mediaType = null;
        if (fileName != null && fileName.endsWith(".csv")) {
            mediaType = detectCsv(InputStreamUtil.asStream(header), md);
        } else {
            mediaType = tika.getDetector().detect(TikaInputStream.get(InputStreamUtil.asStream(header)), md);
            // manually call the csv detector if it is a text file that is not matched.
            // this is needed, and cannot be added to the /META-INF/services/org.apache.tika.detect.Detector file since there is no guarantee of order
            // we first want to detect the type from the core tika mimetypes.
            // then if we didnt get a concrete type attempt to parse it via csv
            if (mediaType.equals(MediaType.TEXT_PLAIN)) {
                mediaType = detectCsv(InputStreamUtil.asStream(header), md);
            } else if (mediaType.equals(MediaType.APPLICATION_XML)) {
                XmlRootExtractor rowTagExtractor = new XmlRootExtractor();
                QName root = rowTagExtractor.extractRootElement(InputStreamUtil.asStream(header));
                if (root != null) {
                    String rowTag = root.getLocalPart();
                    md.set("rowTag", rowTag);
                } else {
                    // unable to detect RowTag from XML!!
                }
            }
        }
        if (mediaType == null) {
            mediaType = MediaType.OCTET_STREAM;
        }
        FileMetadata fileMetadata = new FileMetadata(mediaType.toString());
        fileMetadata.addProperties(metadataToMap(md));
        fileMetadata.setSubType(mediaType.getSubtype());
        String encoding = charset.name();
        fileMetadata.setEncoding(StringUtils.isBlank(encoding) ? StandardCharsets.UTF_8.name() : encoding);
        return fileMetadata;
    }

    private static MediaType detectCsv(InputStream inputStream, Metadata md) throws Exception {
        CSVDetector d = new CSVDetector();
        return d.d

    }

    private static Map<String, String> metadataToMap(Metadata metadata) {
        Map<String, String> map = new HashMap<>();
        for (String name : metadata.names()) {
            String firstValue = metadata.get(name);
            map.put(name, firstValue);
        }
        return map;
    }

    /**
     * Detect metadata for a specific file
     *
     * @param file the file to inspect
     * @return the metadata for that file
     */
    public static FileMetadata detectFromFile(File file) throws Exception {
        InputStream inputStream = FileUtils.openInputStream(file);
        return detectFromStream(inputStream, file.getName());
    }
}


public static FileMetadata detectFromFile(File file) throws Exception {
        InputStream inputStream = FileUtils.openInputStream(file);
        return detectFromStream(inputStream, file.getName());
    }


public void setStreamIcon(StreamIcon streamIcon)

/*! ******************************************************************************
 *
 * Pentaho Data Integration
 *
 *
 *******************************************************************************
 *
 *
 ******************************************************************************/
package org.pentaho.di.trans.step.errorhandling;

import org.pentaho.di.core.Const;
import org.pentaho.di.trans.step.StepMeta;

public class Stream implements StreamInterface {

    private String description;

    private StreamType streamType;

    private StepMeta stepMeta;

    private StreamIcon streamIcon;

    private Object subject;

    /**
     * @param streamType
     * @param stepname
     * @param stepMeta
     * @param description
     */
    public Stream(StreamType streamType, StepMeta stepMeta, String description, StreamIcon streamIcon, Object subject) {
        this.streamType = streamType;
        this.stepMeta = stepMeta;
        this.description = description;
        this.streamIcon = streamIcon;
        this.subject = subject;
    }

    public Stream(StreamInterface stream) {
        this(stream.getStreamType(), stream.getStepMeta(), stream.getDescription(), stream.getStreamIcon(), stream.getSubject());
    }

    public String toString() {
        if (stepMeta == null) {
            return "Stream type " + streamType + Const.CR + description;
        } else {
            return "Stream type " + streamType + " for step '" + stepMeta.getName() + "'" + Const.CR + description;
        }
    }

    @Override
    public boolean equals(Object obj) {
        if (!(obj instanceof StreamInterface)) {
            return false;
        }
        if (obj == this) {
            return true;
        }
        StreamInterface stream = (StreamInterface) obj;
        if (description.equals(stream.getDescription())) {
            return true;
        }
        return false;
    }

    @Override
    public int hashCode() {
        return description.hashCode();
    }

    public String getStepname() {
        if (stepMeta == null) {
            return null;
        }
        return stepMeta.getName();
    }

    /**
     * @return the description
     */
    public String getDescription() {
        return description;
    }

    /**
     * @param description
     *          the description to set
     */
    public void setDescription(String description) {
        this.description = description;
    }

    /**
     * @return the streamType
     */
    public StreamType getStreamType() {
        return streamType;
    }

    /**
     * @param streamType
     *          the streamType to set
     */
    public void setStreamType(StreamType streamType) {
        this.streamType = streamType;
    }

    /**
     * @return the stepMeta
     */
    public StepMeta getStepMeta() {
        return stepMeta;
    }

    /**
     * @param stepMeta
     *          the stepMeta to set
     */
    public void setStepMeta(StepMeta stepMeta) {
        this.stepMeta = stepMeta;
    }

    /**
     * @return the streamIcon
     */
    public StreamIcon getStreamIcon() {
        return streamIcon;
    }

    /**
     * @param streamIcon
     *          the streamIcon to set
     */

{
        this.streamIcon = streamIcon;
    }

    /**
     * @return the subject
     */
    public Object getSubject() {
        return subject;
    }

    /**
     * @param subject
     *          the subject to set
     */
    public void setSubject(Object subject) {
        this.subject = subject;
    }
}


/*! ******************************************************************************
 *
 * Pentaho Data Integration
 *
 *
 *******************************************************************************
 *
 *
 ******************************************************************************/
package org.pentaho.di.trans.step.errorhandling;

import org.pentaho.di.core.Const;
import org.pentaho.di.trans.step.StepMeta;

public class Stream implements StreamInterface {

    private String description;

    private StreamType streamType;

    private StepMeta stepMeta;

    private StreamIcon streamIcon;

    private Object subject;

    /**
     * @param streamType
     * @param stepname
     * @param stepMeta
     * @param description
     */
    public Stream(StreamType streamType, StepMeta stepMeta, String description, StreamIcon streamIcon, Object subject) {
        this.streamType = streamType;
        this.stepMeta = stepMeta;
        this.description = description;
        this.streamIcon = streamIcon;
        this.subject = subject;
    }

    public Stream(StreamInterface stream) {
        this(stream.getStreamType(), stream.getStepMeta(), stream.getDescription(), stream.getStreamIcon(), stream.getSubject());
    }

    public String toString() {
        if (stepMeta == null) {
            return "Stream type " + streamType + Const.CR + description;
        } else {
            return "Stream type " + streamType + " for step '" + stepMeta.getName() + "'" + Const.CR + description;
        }
    }

    @Override
    public boolean equals(Object obj) {
        if (!(obj instanceof StreamInterface)) {
            return false;
        }
        if (obj == this) {
            return true;
        }
        StreamInterface stream = (StreamInterface) obj;
        if (description.equals(stream.getDescription())) {
            return true;
        }
        return false;
    }

    @Override
    public int hashCode() {
        return description.hashCode();
    }

    public String getStepname() {
        if (stepMeta == null) {
            return null;
        }
        return stepMeta.getName();
    }

    /**
     * @return the description
     */
    public String getDescription() {
        return description;
    }

    /**
     * @param description
     *          the description to set
     */
    public void setDescription(String description) {
        this.description = description;
    }

    /**
     * @return the streamType
     */
    public StreamType getStreamType() {
        return streamType;
    }

    /**
     * @param streamType
     *          the streamType to set
     */
    public void setStreamType(StreamType streamType) {
        this.streamType = streamType;
    }

    /**
     * @return the stepMeta
     */
    public StepMeta getStepMeta() {
        return stepMeta;
    }

    /**
     * @param stepMeta
     *          the stepMeta to set
     */
    public void setStepMeta(StepMeta stepMeta) {
        this.stepMeta = stepMeta;
    }

    /**
     * @return the streamIcon
     */
    public StreamIcon getStreamIcon()

    /**
     * @param streamIcon
     *          the streamIcon to set
     */
    public void setStreamIcon(StreamIcon streamIcon) {
        this.streamIcon = streamIcon;
    }

    /**
     * @return the subject
     */
    public Object getSubject() {
        return subject;
    }

    /**
     * @param subject
     *          the subject to set
     */
    public void setSubject(Object subject) {
        this.subject = subject;
    }
}


/*! ******************************************************************************
 *
 * Pentaho Data Integration
 *
 *
 *******************************************************************************
 *
 *
 ******************************************************************************/
package org.pentaho.di.trans.step.errorhandling;

import org.pentaho.di.core.Const;
import org.pentaho.di.trans.step.StepMeta;

public class Stream implements StreamInterface {

    private String description;

    private StreamType streamType;

    private StepMeta stepMeta;

    private StreamIcon streamIcon;

    private Object subject;

    /**
     * @param streamType
     * @param stepname
     * @param stepMeta
     * @param description
     */
    public Stream(StreamType streamType, StepMeta stepMeta, String description, StreamIcon streamIcon, Object subject) {
        this.streamType = streamType;
        this.stepMeta = stepMeta;
        this.description = description;
        this.streamIcon = streamIcon;
        this.subject = subject;
    }

    public Stream(StreamInterface stream) {
        this(stream.getStreamType(), stream.getStepMeta(), stream.getDescription(), stream.getStreamIcon(), stream.getSubject());
    }

    public String toString() {
        if (stepMeta == null) {
            return "Stream type " + streamType + Const.CR + description;
        } else {
            return "Stream type " + streamType + " for step '" + stepMeta.getName() + "'" + Const.CR + description;
        }
    }

    @Override
    public boolean equals(Object obj) {
        if (!(obj instanceof StreamInterface)) {
            return false;
        }
        if (obj == this) {
            return true;
        }
        StreamInterface stream = (StreamI

        if (description.equals(stream.getDescription())) {
            return true;
        }
        return false;
    }

    @Override
    public int hashCode() {
        return description.hashCode();
    }

    public String getStepname() {
        if (stepMeta == null) {
            return null;
        }
        return stepMeta.getName();
    }

    /**
     * @return the description
     */
    public String getDescription() {
        return description;
    }

    /**
     * @param description
     *          the description to set
     */
    public void setDescription(String description) {
        this.description = description;
    }

    /**
     * @return the streamType
     */
    public StreamType getStreamType() {
        return streamType;
    }

    /**
     * @param streamType
     *          the streamType to set
     */
    public void setStreamType(StreamType streamType) {
        this.streamType = streamType;
    }

    /**
     * @return the stepMeta
     */
    public StepMeta getStepMeta() {
        return stepMeta;
    }

    /**
     * @param stepMeta
     *          the stepMeta to set
     */
    public void setStepMeta(StepMeta stepMeta) {
        this.stepMeta = stepMeta;
    }

    /**
     * @return the streamIcon
     */
    public StreamIcon getStreamIcon() {
        return streamIcon;
    }

    /**
     * @param streamIcon
     *          the streamIcon to set
     */
    public void setStreamIcon(StreamIcon streamIcon) {
        this.streamIcon = streamIcon;
    }

    /**
     * @return the subject
     */
    public Object getSubject() {
        return subject;
    }

    /**
     * @param subject
     *          the subject to set
     */
    public void setSubject(Object subject) {
        this.subject = subject;
    }
}


public String getDescription() {
        return description;
    }

/*! ******************************************************************************
 *
 * Pentaho Data Integration
 *
 *
 *******************************************************************************
 *
 *
 ******************************************************************************/
package org.pentaho.di.trans.step.errorhandling;

import org.pentaho.di.core.Const;
import org.pentaho.di.trans.step.StepMeta;

public class Stream implements StreamInterface {

    private String description;

    private StreamType streamType;

    private StepMeta stepMeta;

    private StreamIcon streamIcon;

    private Object subject;

    /**
     * @param streamType
     * @param stepname
     * @param stepMeta
     * @param description
     */
    public Stream(StreamType streamType, StepMeta stepMeta, String description, StreamIcon streamIcon, Object subject) {
        this.streamType = streamType;
        this.stepMeta = stepMeta;
        this.description = description;
        this.streamIcon = streamIcon;
        this.subject = subject;
    }

    public Stream(StreamInterface stream) {
        this(stream.getStreamType(), stream.getStepMeta(), stream.getDescription(), stream.getStreamIcon(), stream.getSubject());
    }

    public String toString() {
        if (stepMeta == null) {
            return "Stream type " + streamType + Const.CR + description;
        } else {
            return "Stream type " + streamType + " for step '" + stepMeta.getName() + "'" + Const.CR + description;
        }
    }

    @Override
    public boolean equals(Object obj) {
        if (!(obj instanceof StreamInterface)) {
            return false;
        }
        if (obj == this) {
            return true;
        }
        StreamInterface stream = (StreamInterface) obj;
        if (description.equals(stream.getDescription())) {
            return true;
        }
        return false;
    }

    @Override
    public int hashCode() {
        return description.hashCode();
    }

    public String getStepname() {
        if (stepMeta == null) {
            return null;
        }
        return stepMeta.getName();
    }

    /**
     * @return the description
     */

    /**
     * @param description
     *          the description to set
     */
    public void setDescription(String description) {
        this.description = description;
    }

    /**
     * @return the streamType
     */
    public StreamType getStreamType() {
        return streamType;
    }

    /**
     * @param streamType
     *          the streamType to set
     */
    public void setStreamType(StreamType streamType) {
        this.streamType = streamType;
    }

    /**
     * @return the stepMeta
     */
    public StepMeta getStepMeta() {
        return stepMeta;
    }

    /**
     * @param stepMeta
     *          the stepMeta to set
     */
    public void setStepMeta(StepMeta stepMeta) {
        this.stepMeta = stepMeta;
    }

    /**
     * @return the streamIcon
     */
    public StreamIcon getStreamIcon() {
        return streamIcon;
    }

    /**
     * @param streamIcon
     *          the streamIcon to set
     */
    public void setStreamIcon(StreamIcon streamIcon) {
        this.streamIcon = streamIcon;
    }

    /**
     * @return the subject
     */
    public Object getSubject() {
        return subject;
    }

    /**
     * @param subject
     *          the subject to set
     */
    public void setSubject(Object subject) {
        this.subject = subject;
    }
}


/**
 *    geo-platform
 *    Rich webgis framework
 *    http://geo-platform.org
 *   ====================================================================
 *
 *   ====================================================================
 */
package org.geosdi.geoplatform.experimental.el.threadpool.spi.finder;

import org.geosdi.geoplatform.threadpool.support.spi.finder.GPThreadPoolExecutorFinderSupport;
import java.util.concurrent.ExecutorService;

/**
 * @author Giuseppe La Scaleia - CNR IMAA geoSDI Group
 * @email example@nnthink.com
 */
public interface GPThreadPoolExecutorFinder extends GPThreadPoolExecutorFinderSupport<ExecutorService> {

    /**
     * @return {@link ExecutorService}
     */


// Oracle - initial API and implementation from Oracle TopLink
package org.eclipse.persistence.testing.tests.jpa.fieldaccess.advanced;

import org.eclipse.persistence.testing.framework.junit.JUnitTestCase;
import junit.framework.TestSuite;
import junit.framework.Test;

/**
 *
Purpose: To collect the tests that will run against Application Server only.
 */
public class FAServerTestSuite extends TestSuite {

{
        JUnitTestCase.initializePlatform();
        TestSuite suite = new TestSuite();
        suite.setName("Fieldaccess Advanced ServerTestSuite");
        suite.addTest(AdvancedJPAJunitTest.suite());
        suite.addTest(AdvancedJunitTest.suite());
        suite.addTest(CallbackEventJUnitTestSuite.suite());
        suite.addTest(EntityManagerJUnitTestSuite.suiteSpring());
        suite.addTest(ExtendedPersistenceContextJUnitTestSuite.suite());
        suite.addTest(JoinedAttributeAdvancedJunitTest.suiteSpring());
        suite.addTest(NamedNativeQueryJUnitTest.suite());
        suite.addTest(OptimisticConcurrencyJUnitTestSuite.suite());
        suite.addTest(ReportQueryAdvancedJUnitTest.suite());
        suite.addTest(ReportQueryConstructorExpressionTestSuite.suite());
        suite.addTest(ReportQueryMultipleReturnTestSuite.suite());
        suite.addTest(SQLResultSetMappingTestSuite.suite());
        suite.addTest(UpdateAllQueryAdvancedJunitTest.suite());
        return suite;
    }
}


// Oracle - initial API and implementation from Oracle TopLink
package org.eclipse.persistence.testing.tests.jpa.fieldaccess.advanced;

import org.eclipse.persistence.testing.framework.junit.JUnitTestCase;
import junit.framework.TestSuite;
import junit.framework.Test;

/**
 *
Purpose: To collect the tests that will run against Application Server only.
 */
public class FAServerTestSuite extends TestSuite {

    public static Test suite() {
        JUnitTestCase.initializePlatform();
        TestSuite suite = new TestSuite();
        suite.setName("Fieldaccess Advanced ServerTestSuite");
        suite.addTest(AdvancedJPAJunitTest.suite());
        suite.addTest(AdvancedJunitTest.suite());
        suite.addTest(CallbackEventJUnitTestSuite.suite());
        suite.addTest(EntityManagerJUnitTestSuite.suiteSpring());
        suite.addTest(ExtendedPersistenceContextJUnitTestSuite.suite());
        suite.addTest(JoinedAttributeAdvancedJunitTest.suiteSpring());
        suite.addTest(NamedNativeQueryJUnitTest.suite());
        suite.addTest(OptimisticConcurrencyJUnitTestSuite.suite());
        suite.addTest(ReportQueryAdvancedJUnitTest.suite());
        suite.add

        suite.addTest(ReportQueryMultipleReturnTestSuite.suite());
        suite.addTest(SQLResultSetMappingTestSuite.suite());
        suite.addTest(UpdateAllQueryAdvancedJunitTest.suite());
        return suite;
    }
}


public static String formatJson(String content) throws IOException

package io.apicurio.hub.core.util;

import java.io.IOException;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import com.fasterxml.jackson.dataformat.yaml.YAMLFactory;
import com.fasterxml.jackson.dataformat.yaml.YAMLGenerator;

/**
 * @author example@nnthink.com
 */
public class FormatUtils {

    private static ObjectMapper jsonMapper = new ObjectMapper();

    private static ObjectMapper yamlMapper;

    static {
        YAMLFactory factory = new YAMLFactory();
        factory.enable(YAMLGenerator.Feature.MINIMIZE_QUOTES);
        factory.enable(YAMLGenerator.Feature.ALWAYS_QUOTE_NUMBERS_AS_STRINGS);
        yamlMapper = new ObjectMapper(factory);
        jsonMapper.enable(SerializationFeature.INDENT_OUTPUT);
    }

    /**
     * Converts the content from JSON to YAML format.
     * @param content
     * @throws IOException
     */
    public static String jsonToYaml(String content) throws IOException {
        JsonNode tree = jsonMapper.reader().readTree(content);
        return yamlMapper.writeValueAsString(tree);
    }

    /**
     * Converts the content from YAML to JSON format.
     * @param content
     * @throws IOException
     */
    public static String yamlToJson(String content) throws IOException {
        JsonNode tree = yamlMapper.reader().readTree(content);
        return jsonMapper.writeValueAsString(tree);
    }

    /**
     * Takes JSON content and formats with a standard 2 spaces per indent.  This
     * is used to take (potentially) unformatted JSON and convert it to formatted JSON.
     * @param content
     * @throws IOException
     */

{
        // If it's already formatted, do nothing.
        if (content.contains("\n")) {
            return content;
        }
        JsonNode tree = jsonMapper.reader().readTree(content);
        return jsonMapper.writeValueAsString(tree);
    }
}


{
        // If it's already formatted, do nothing.
        if (content.contains("\n")) {
            return content;
        }
        JsonNode tree = jsonMapper.reader().readTree(content);
        return jsonMapper.writeValueAsString(tree);
    }

package io.apicurio.hub.core.util;

import java.io.IOException;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import com.fasterxml.jackson.dataformat.yaml.YAMLFactory;
import com.fasterxml.jackson.dataformat.yaml.YAMLGenerator;

/**
 * @author example@nnthink.com
 */
public class FormatUtils {

    private static ObjectMapper jsonMapper = new ObjectMapper();

    private static ObjectMapper yamlMapper;

    static {
        YAMLFactory factory = new YAMLFactory();
        factory.enable(YAMLGenerator.Feature.MINIMIZE_QUOTES);
        factory.enable(YAMLGenerator.Feature.ALWAYS_QUOTE_NUMBERS_AS_STRINGS);
        yamlMapper = new ObjectMapper(factory);
        jsonMapper.enable(SerializationFeature.INDENT_OUTPUT);
    }

    /**
     * Converts the content from JSON to YAML format.
     * @param content
     * @throws IOException
     */
    public static String jsonToYaml(String content) throws IOException {
        JsonNode tree = jsonMapper.reader().readTree(content);
        return yamlMapper.writeValueAsString(tree);
    }

    /**
     * Converts the content from YAML to JSON format.
     * @param content
     * @throws IOException
     */
    public static String yamlToJson(String content) throws IOException {
        JsonNode tree = yamlMapper.reader().readTree(content);
        return jsonMapper.writeValueAsString(tree);
    }

    /**
     * Takes JSON content and formats with a standard 2 spaces per indent.  This
     * is used to take (potentially) unformatted JSON and convert it to formatted JSON.
     * @param content
     * @throws IOException
     */
    public static String formatJson(String content) throws IOException


package io.apicurio.hub.core.util;

import java.io.IOException;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import com.fasterxml.jackson.dataformat.yaml.YAMLFactory;
import com.fasterxml.jackson.dataformat.yaml.YAMLGenerator;

/**
 * @author example@nnthink.com
 */
public class FormatUtils {

    private static ObjectMapper jsonMapper = new ObjectMapper();

    private static ObjectMapper yamlMapper;

    static {
        YAMLFactory factory = new YAMLFactory();
        factory.enable(YAMLGenerator.Feature.MINIMIZE_QUOTES);
        factory.enable(YAMLGenerator.Feature.ALWAYS_QUOTE_NUMBERS_AS_STRINGS);
        yamlMapper = new ObjectMapper(factory);
        jsonMapper.enable(SerializationFeature.INDENT_OUTPUT);
    }

    /**
     * Converts the content from JSON to YAML format.
     * @param content
     * @throws IOException
     */
    public static String jsonToYaml(String content) throws IOException {
        JsonNode tree = jsonMapper.reader().readTree(content);
        return yamlMapper.writeValueAsString(tree);
    }

    /**
     * Converts the content from YAML to JSON format.
     * @param content
     * @throws IOException
     */
    public static String yamlToJson(String content) throws IOException {
        JsonNode tree = yamlMapper.reader().readTree(content);
        return jsonMapper.writeValueAsString(tree);
    }

    /**
     * Takes JSON content and formats with a standard 2 spaces per indent.  This
     * is used to take (potentially) unformatted JSON and convert it to formatted JSON.
     * @param content
     * @throws IOException
     */
    public static String formatJson(String content) throws IOException {
        // If it's already formatted, do nothing.
        if (content.contains("\n")) {
            return content;
        }
        JsonNode tree = jsonMapper.reader().readTree(content);
        return jsonMapper.writeV


public static String jsonToYaml(String content) throws IOException {
        JsonNode tree = jsonMapper.reader().readTree(content);
        return yamlMapper.writeValueAsString(tree);
    }

package io.apicurio.hub.core.util;

import java.io.IOException;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import com.fasterxml.jackson.dataformat.yaml.YAMLFactory;
import com.fasterxml.jackson.dataformat.yaml.YAMLGenerator;

/**
 * @author example@nnthink.com
 */
public class FormatUtils {

    private static ObjectMapper jsonMapper = new ObjectMapper();

    private static ObjectMapper yamlMapper;

    static {
        YAMLFactory factory = new YAMLFactory();
        factory.enable(YAMLGenerator.Feature.MINIMIZE_QUOTES);
        factory.enable(YAMLGenerator.Feature.ALWAYS_QUOTE_NUMBERS_AS_STRINGS);
        yamlMapper = new ObjectMapper(factory);
        jsonMapper.enable(SerializationFeature.INDENT_OUTPUT);
    }

    /**
     * Converts the content from JSON to YAML format.
     * @param content
     * @throws IOException
     */

    /**
     * Converts the content from YAML to JSON format.
     * @param content
     * @throws IOException
     */
    public static String yamlToJson(String content) throws IOException {
        JsonNode tree = yamlMapper.reader().readTree(content);
        return jsonMapper.writeValueAsString(tree);
    }

    /**
     * Takes JSON content and formats with a standard 2 spaces per indent.  This
     * is used to take (potentially) unformatted JSON and convert it to formatted JSON.
     * @param content
     * @throws IOException
     */
    public static String formatJson(String content) throws IOException {
        // If it's already formatted, do nothing.
        if (content.contains("\n")) {
            return content;
        }
        JsonNode tree = jsonMapper.reader().readTree(content);
        return jsonMapper.writeValueAsString(tree);
    }
}


public void walkAndMultiExpression(MultiExpression expr)

package org.nuxeo.ecm.directory.ldap;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import org.nuxeo.ecm.core.query.QueryParseException;
import org.nuxeo.ecm.core.query.sql.model.BooleanLiteral;
import org.nuxeo.ecm.core.query.sql.model.DateLiteral;
import org.nuxeo.ecm.core.query.sql.model.DoubleLiteral;
import org.nuxeo.ecm.core.query.sql.model.Expression;
import org.nuxeo.ecm.core.query.sql.model.Function;
import org.nuxeo.ecm.core.query.sql.model.IntegerLiteral;
import org.nuxeo.ecm.core.query.sql.model.Literal;
import org.nuxeo.ecm.core.query.sql.model.LiteralList;
import org.nuxeo.ecm.core.query.sql.model.MultiExpression;
import org.nuxeo.ecm.core.query.sql.model.Operand;
import org.nuxeo.ecm.core.query.sql.model.Operator;
import org.nuxeo.ecm.core.query.sql.model.Predicate;
import org.nuxeo.ecm.core.query.sql.model.Reference;
import org.nuxeo.ecm.core.query.sql.model.StringLiteral;
import org.nuxeo.ecm.core.schema.types.Field;
import org.nuxeo.ecm.core.schema.types.primitives.BooleanType;

/**
 * Creates an LDAP query filter from a Nuxeo Expression.
 *
 * @since 10.3
 */
public class LDAPFilterBuilder {

    protected static final String DATE_CAST = "DATE";

    protected final LDAPDirectory directory;

    public StringBuilder filter = new StringBuilder();

    public int paramIndex = 0;

    public final List<Serializable> params = new ArrayList<>();

    public LDAPFilterBuilder(LDAPDirectory directory) {
        this.directory = directory;
    }

    public void walk(Expression expression) {
        if (expression instanceof MultiExpression && ((MultiExpression) expression).predicates.isEmpty()) {
            // special-case empty query
            return;
        } else {
            walkExpression(expression);
        }
    }

    public void walkExpression(Expression expr) {
        Operator op = expr.operator;
        Operand lvalue = expr.lvalue;
        Operand rvalue = expr.rvalue;
        Reference ref = lvalue instanceof Reference ? (Reference) lvalue : null;
        String name = ref != null ? ref.name : null;
        String cast = ref != null ? ref.cast : null;
        if (DATE_CAST.equals(cast)) {
            checkDateLiteralForCast(op, rvalue, name);
        }
        if (op == Operator.SUM) {
            throw new QueryParseException("SUM");
        } else if (op == Operator.SUB) {
            throw new QueryParseException("SUB");
        } else if (op == Operator.MUL) {
            throw new QueryParseException("MUL");
        } else if (op == Operator.DIV) {
            throw new QueryParseException("DIV");
        } else if (op == Operator.LT) {
            walkLt(lvalue, rvalue);
        } else if (op == Operator.GT) {
            walkGt(lvalue, rvalue);
        } else if (op == Operator.EQ) {
            walkEq(lvalue, rvalue);
        } else if (op == Operator.NOTEQ) {
            walkNotEq(lvalue, rvalue);
        } else if (op == Operator.LTEQ) {
            walkLtEq(lvalue, rvalue);
        } else if (op == Operator.GTEQ) {
            walkGtEq(lvalue, rvalue);
        } else if (op == Operator.AND) {
            if (expr instanceof MultiExpression) {
                walkAndMultiExpression((MultiExpression) expr);
            } else {
                walkAnd(expr);
            }
        } else if (op == Operator.NOT) {
            walkNot(lvalue);
        } else if (op == Operator.OR) {
            if (expr instanceof MultiExpression) {
                walkOrMultiExpression((MultiExpression) expr);
            } else {
                walkOr(expr);
            }
        } else if (op == Operator.LIKE) {
            walkLike(lvalue, rvalue, true, false);
        } else if (op == Operator.ILIKE) {
            walkLike(lvalue, rvalue, true, true);
        } else if (op == Operator.NOTLIKE) {
            walkLike(lvalue, rvalue, false, false);
        } else if (op == Operator.NOTILIKE) {
            walkLike(lvalue, rvalue, false, true);
        } else if (op == Operator.IN) {
            walkIn(lvalue, rvalue, true);
        } else if (op == Operator.NOTIN) {
            walkIn(lvalue, rvalue, false);
        } else if (op == Operator.ISNULL) {
            walkIsNull(lvalue);
        } else if (op == Operator.ISNOTNULL) {
            walkIsNotNull(lvalue);
        } else if (op == Operator.BETWEEN) {
            walkBetween(lvalue, rvalue, true);
        } else if (op == Operator.NOTBETWEEN) {
            walkBetween(lvalue, rvalue, false);
        } else {
            throw new QueryParseException("Unknown operator: " + op);
        }
    }

    protected void checkDateLiteralForCast(Operator op, Operand value, String name) {
        if (op == Operator.BETWEEN || op == Operator.NOTBETWEEN) {
            LiteralList l = (LiteralList) value;
            checkDateLiteralForCast(l.get(0), name);
            checkDateLiteralForCast(l.get(1), name);
        } else {
            checkDateLiteralForCast(value, name);
        }
    }

    protected void checkDateLiteralForCast(Operand value, String name) {
        if (value instanceof DateLiteral && !((DateLiteral) value).onlyDate) {
            throw new QueryParseException("DATE() cast must be used with DATE literal, not TIMESTAMP: " + name);
        }
    }

    public void walkNot(Operand value) {
        filter.append("(!");
        walkOperand(value);
        filter.append(')');
    }

    public void walkIsNull(Operand value) {
        filter.append("(!");
        walkIsNotNull(value);
        filter.append(')');
    }

    public void walkIsNotNull(Operand value) {
        filter.append('(');
        walkReference(value);
        filter.append("=*)");
    }

{
        walkMulti("&", expr.predicates);
    }

    public void walkAnd(Expression expr) {
        walkMulti("&", Arrays.asList(expr.lvalue, expr.rvalue));
    }

    public void walkOrMultiExpression(MultiExpression expr) {
        walkMulti("|", expr.predicates);
    }

    public void walkOr(Expression expr) {
        walkMulti("|", Arrays.asList(expr.lvalue, expr.rvalue));
    }

    protected void walkMulti(String op, List<? extends Operand> values) {
        if (values.size() == 1) {
            walkOperand(values.get(0));
        } else {
            filter.append('(');
            filter.append(op);
            for (Operand value : values) {
                walkOperand(value);
            }
            filter.append(')');
        }
    }

    public void walkEq(Operand lvalue, Operand rvalue) {
        walkBinOp("=", lvalue, rvalue);
    }

    public void walkNotEq(Operand lvalue, Operand rvalue) {
        filter.append("(!");
        walkEq(lvalue, rvalue);
        filter.append(')');
    }

    public void walkLt(Operand lvalue, Operand rvalue) {
        walkBinOp("<", lvalue, rvalue);
    }

    public void walkGt(Operand lvalue, Operand rvalue) {
        walkBinOp(">", lvalue, rvalue);
    }

    public void walkLtEq(Operand lvalue, Operand rvalue) {
        walkBinOp("<=", lvalue, rvalue);
    }

    public void walkGtEq(Operand lvalue, Operand rvalue) {
        walkBinOp(">=", lvalue, rvalue);
    }

    protected void walkBinOp(String op, Operand lvalue, Operand rvalue) {
        filter.append('(');
        Field field = walkReference(lvalue);
        filter.append(op);
        if (field.getType() instanceof BooleanType) {
            rvalue = makeBoolean(rvalue);
        }
        walkLiteral(rvalue);
        filter.append(')');
    }

    protected Operand makeBoolean(Operand rvalue) {
        if (rvalue instanceof BooleanLiteral) {
            return rvalue;
        }
        long v;
        if (!(rvalue instanceof IntegerLiteral) || ((v = ((IntegerLiteral) rvalue).value) != 0 && v != 1)) {
            throw new QueryParseException("Boolean expressions require boolean or literal 0 or 1 as right argument");
        }
        return new BooleanLiteral(v == 1);
    }

    public void walkBetween(Operand lvalue, Operand rvalue, boolean positive) {
        LiteralList list = (LiteralList) rvalue;
        Literal left = list.get(0);
        Literal right = list.get(1);
        if (!positive) {
            filter.append("(!");
        }
        filter.append("(&");
        walkGtEq(lvalue, left);
        walkLtEq(lvalue, right);
        filter.append(')');
        if (!positive) {
            filter.append(')');
        }
    }

    public void walkIn(Operand lvalue, Operand rvalue, boolean positive) {
        if (!positive) {
            filter.append("(!");
        }
        filter.append("(|");
        for (Literal value : (LiteralList) rvalue) {
            walkEq(lvalue, value);
        }
        filter.append(')');
        if (!positive) {
            filter.append(')');
        }
    }

    public void walkLike(Operand lvalue, Operand rvalue, boolean positive, boolean caseInsensitive) {
        if (!(rvalue instanceof StringLiteral)) {
            throw new QueryParseException("Invalid LIKE, right hand side must be a string: " + rvalue);
        }
        String like = ((StringLiteral) rvalue).value;
        if (caseInsensitive) {
            like = like.toLowerCase();
        }
        if (!positive) {
            filter.append("(!");
        }
        filter.append('(');
        walkReference(lvalue);
        filter.append('=');
        walkLikeWildcard(like);
        filter.append(')');
        if (!positive) {
            filter.append(')');
        }
    }

    /**
     * Turns a NXQL LIKE pattern into an LDAP wildcard.
     * <p>
     * % and _ are standard wildcards, and \ escapes them.
     */
    public void walkLikeWildcard(String like) {
        StringBuilder param = new StringBuilder();
        char[] chars = like.toCharArray();
        boolean escape = false;
        for (int i = 0; i < chars.length; i++) {
            char c = chars[i];
            boolean escapeNext = false;
            if (escape) {
                param.append(c);
            } else {
                switch(c) {
                    case '%':
                        if (param.length() != 0) {
                            addFilterParam(param.toString());
                            param.setLength(0);
                        }
                        filter.append('*');
                        break;
                    case // interpret it as an escaped _, not a wildcard
                    '_':
                        param.append(c);
                        break;
                    case '\\':
                        escapeNext = true;
                        break;
                    default:
                        param.append(c);
                        break;
                }
            }
            escape = escapeNext;
        }
        if (escape) {
            throw new QueryParseException("Invalid LIKE parameter ending with escape character");
        }
        if (param.length() != 0) {
            addFilterParam(param.toString());
        }
    }

    public void walkOperand(Operand operand) {
        if (operand instanceof Literal) {
            walkLiteral((Literal) operand);
        } else if (operand instanceof Function) {
            walkFunction((Function) operand);
        } else if (operand instanceof Expression) {
            walkExpression((Expression) operand);
        } else if (operand instanceof Reference) {
            walkReference((Reference) operand);
        } else {
            throw new QueryParseException("Unknown operand: " + operand);
        }
    }

    public void walkLiteral(Operand operand) {
        if (!(operand instanceof Literal)) {
            throw new QueryParseException("Requires literal instead of: " + operand);
        }
        Literal lit = (Literal) operand;
        if (lit instanceof BooleanLiteral) {
            walkBooleanLiteral((BooleanLiteral) lit);
        } else if (lit instanceof DateLiteral) {
            walkDateLiteral((DateLiteral) lit);
        } else if (lit instanceof DoubleLiteral) {
            walkDoubleLiteral((DoubleLiteral) lit);
        } else if (lit instanceof IntegerLiteral) {
            walkIntegerLiteral((IntegerLiteral) lit);
        } else if (lit instanceof StringLiteral) {
            walkStringLiteral((StringLiteral) lit);
        } else {
            throw new QueryParseException("Unknown literal: " + lit);
        }
    }

    public void walkBooleanLiteral(BooleanLiteral lit) {
        addFilterParam(Boolean.valueOf(lit.value));
    }

    public void walkDateLiteral(DateLiteral lit) {
        if (lit.onlyDate) {
            throw new QueryParseException("Cannot use only date in LDAP query: " + lit);
        }
        // let LDAP library serialize it
        addFilterParam(lit.toCalendar());
    }

    public void walkDoubleLiteral(DoubleLiteral lit) {
        addFilterParam(Double.valueOf(lit.value));
    }

    public void walkIntegerLiteral(IntegerLiteral lit) {
        addFilterParam(Long.valueOf(lit.value));
    }

    public void walkStringLiteral(StringLiteral lit) {
        addFilterParam(lit.value);
    }

    protected void addFilterParam(Serializable value) {
        filter.append('{');
        filter.append(paramIndex++);
        filter.append('}');
        params.add(value);
    }

    public Object walkFunction(Function func) {
        throw new QueryParseException(func.name);
    }

    public Field walkReference(Operand value) {
        if (!(value instanceof Reference)) {
            throw new QueryParseException("Invalid query, left hand side must be a property: " + value);
        }
        String name = ((Reference) value).name;
        if (directory.isReference(name)) {
            throw new QueryParseException("Column: " + name + " is a reference and cannot be queried for directory: " + directory.getName());
        }
        Field field = directory.getSchemaFieldMap().get(name);
        if (field == null) {
            throw new QueryParseException("No column: " + name + " for directory: " + directory.getName());
        }
        String backend = directory.getFieldMapper().getBackendField(name);
        filter.append(backend);
        return field;
    }
}


{
        addFilterParam(lit.value);
    }

package org.nuxeo.ecm.directory.ldap;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import org.nuxeo.ecm.core.query.QueryParseException;
import org.nuxeo.ecm.core.query.sql.model.BooleanLiteral;
import org.nuxeo.ecm.core.query.sql.model.DateLiteral;
import org.nuxeo.ecm.core.query.sql.model.DoubleLiteral;
import org.nuxeo.ecm.core.query.sql.model.Expression;
import org.nuxeo.ecm.core.query.sql.model.Function;
import org.nuxeo.ecm.core.query.sql.model.IntegerLiteral;
import org.nuxeo.ecm.core.query.sql.model.Literal;
import org.nuxeo.ecm.core.query.sql.model.LiteralList;
import org.nuxeo.ecm.core.query.sql.model.MultiExpression;
import org.nuxeo.ecm.core.query.sql.model.Operand;
import org.nuxeo.ecm.core.query.sql.model.Operator;
import org.nuxeo.ecm.core.query.sql.model.Predicate;
import org.nuxeo.ecm.core.query.sql.model.Reference;
import org.nuxeo.ecm.core.query.sql.model.StringLiteral;
import org.nuxeo.ecm.core.schema.types.Field;
import org.nuxeo.ecm.core.schema.types.primitives.BooleanType;

/**
 * Creates an LDAP query filter from a Nuxeo Expression.
 *
 * @since 10.3
 */
public class LDAPFilterBuilder {

    protected static final String DATE_CAST = "DATE";

    protected final LDAPDirectory directory;

    public StringBuilder filter = new StringBuilder();

    public int paramIndex = 0;

    public final List<Serializable> params = new ArrayList<>();

    public LDAPFilterBuilder(LDAPDirectory directory) {
        this.directory = directory;
    }

    public void walk(Expression expression) {
        if (expression instanceof MultiExpression && ((MultiExpression) expression).predicates.isEmpty()) {
            // special-case empty query
            return;
        } else {
            walkExpression(expression);
        }
    }

    public void walkExpression(Expression expr) {
        Operator op = expr.operator;
        Operand lvalue = expr.lvalue;
        Operand rvalue = expr.rvalue;
        Reference ref = lvalue instanceof Reference ? (Reference) lvalue : null;
        String name = ref != null ? ref.name : null;
        String cast = ref != null ? ref.cast : null;
        if (DATE_CAST.equals(cast)) {
            checkDateLiteralForCast(op, rvalue, name);
        }
        if (op == Operator.SUM) {
            throw new QueryParseException("SUM");
        } else if (op == Operator.SUB) {
            throw new QueryParseException("SUB");
        } else if (op == Operator.MUL) {
            throw new QueryParseException("MUL");
        } else if (op == Operator.DIV) {
            throw new QueryParseException("DIV");
        } else if (op == Operator.LT) {
            walkLt(lvalue, rvalue);
        } else if (op == Operator.GT) {
            walkGt(lvalue, rvalue);
        } else if (op == Operator.EQ) {
            walkEq(lvalue, rvalue);
        } else if (op == Operator.NOTEQ) {
            walkNotEq(lvalue, rvalue);
        } else if (op == Operator.LTEQ) {
            walkLtEq(lvalue, rvalue);
        } else if (op == Operator.GTEQ) {
            walkGtEq(lvalue, rvalue);
        } else if (op == Operator.AND) {
            if (expr instanceof MultiExpression) {
                walkAndMultiExpression((MultiExpression) expr);
            } else {
                walkAnd(expr);
            }
        } else if (op == Operator.NOT) {
            walkNot(lvalue);
        } else if (op == Operator.OR) {
            if (expr instanceof MultiExpression) {
                walkOrMultiExpression((MultiExpression) expr);
            } else {
                walkOr(expr);
            }
        } else if (op == Operator.LIKE) {
            walkLike(lvalue, rvalue, true, false);
        } else if (op == Operator.ILIKE) {
            walkLike(lvalue, rvalue, true, true);
        } else if (op == Operator.NOTLIKE) {
            walkLike(lvalue, rvalue, false, false);
        } else if (op == Operator.NOTILIKE) {
            walkLike(lvalue, rvalue, false, true);
        } else if (op == Operator.IN) {
            walkIn(lvalue, rvalue, true);
        } else if (op == Operator.NOTIN) {
            walkIn(lvalue, rvalue, false);
        } else if (op == Operator.ISNULL) {
            walkIsNull(lvalue);
        } else if (op == Operator.ISNOTNULL) {
            walkIsNotNull(lvalue);
        } else if (op == Operator.BETWEEN) {
            walkBetween(lvalue, rvalue, true);
        } else if (op == Operator.NOTBETWEEN) {
            walkBetween(lvalue, rvalue, false);
        } else {
            throw new QueryParseException("Unknown operator: " + op);
        }
    }

    protected void checkDateLiteralForCast(Operator op, Operand value, String name) {
        if (op == Operator.BETWEEN || op == Operator.NOTBETWEEN) {
            LiteralList l = (LiteralList) value;
            checkDateLiteralForCast(l.get(0), name);
            checkDateLiteralForCast(l.get(1), name);
        } else {
            checkDateLiteralForCast(value, name);
        }
    }

    protected void checkDateLiteralForCast(Operand value, String name) {
        if (value instanceof DateLiteral && !((DateLiteral) value).onlyDate) {
            throw new QueryParseException("DATE() cast must be used with DATE literal, not TIMESTAMP: " + name);
        }
    }

    public void walkNot(Operand value) {
        filter.append("(!");
        walkOperand(value);
        filter.append(')');
    }

    public void walkIsNull(Operand value) {
        filter.append("(!");
        walkIsNotNull(value);
        filter.append(')');
    }

    public void walkIsNotNull(Operand value) {
        filter.append('(');
        walkReference(value);
        filter.append("=*)");
    }

    public void walkAndMultiExpression(MultiExpression expr) {
        walkMulti("&", expr.predicates);
    }

    public void walkAnd(Expression expr) {
        walkMulti("&", Arrays.asList(expr.lvalue, expr.rvalue));
    }

    public void walkOrMultiExpression(MultiExpression expr) {
        walkMulti("|", expr.predicates);
    }

    public void walkOr(Expression expr) {
        walkMulti("|", Arrays.asList(expr.lvalue, expr.rvalue));
    }

    protected void walkMulti(String op, List<? extends Operand> values) {
        if (values.size() == 1) {
            walkOperand(values.get(0));
        } else {
            filter.append('(');
            filter.append(op);
            for (Operand value : values) {
                walkOperand(value);
            }
            filter.append(')');
        }
    }

    public void walkEq(Operand lvalue, Operand rvalue) {
        walkBinOp("=", lvalue, rvalue);
    }

    public void walkNotEq(Operand lvalue, Operand rvalue) {
        filter.append("(!");
        walkEq(lvalue, rvalue);
        filter.append(')');
    }

    public void walkLt(Operand lvalue, Operand rvalue) {
        walkBinOp("<", lvalue, rvalue);
    }

    public void walkGt(Operand lvalue, Operand rvalue) {
        walkBinOp(">", lvalue, rvalue);
    }

    public void walkLtEq(Operand lvalue, Operand rvalue) {
        walkBinOp("<=", lvalue, rvalue);
    }

    public void walkGtEq(Operand lvalue, Operand rvalue) {
        walkBinOp(">=", lvalue, rvalue);
    }

    protected void walkBinOp(String op, Operand lvalue, Operand rvalue) {
        filter.append('(');
        Field field = walkReference(lvalue);
        filter.append(op);
        if (field.getType() instanceof BooleanType) {
            rvalue = makeBoolean(rvalue);
        }
        walkLiteral(rvalue);
        filter.append(')');
    }

    protected Operand makeBoolean(Operand rvalue) {
        if (rvalue instanceof BooleanLiteral) {
            return rvalue;
        }
        long v;
        if (!(rvalue instanceof IntegerLiteral) || ((v = ((IntegerLiteral) rvalue).value) != 0 && v != 1)) {
            throw new QueryParseException("Boolean expressions require boolean or literal 0 or 1 as right argument");
        }
        return new BooleanLiteral(v == 1);
    }

    public void walkBetween(Operand lvalue, Operand rvalue, boolean positive) {
        LiteralList list = (LiteralList) rvalue;
        Literal left = list.get(0);
        Literal right = list.get(1);
        if (!positive) {
            filter.append("(!");
        }
        filter.append("(&");
        walkGtEq(lvalue, left);
        walkLtEq(lvalue, right);
        filter.append(')');
        if (!positive) {
            filter.append(')');
        }
    }

    public void walkIn(Operand lvalue, Operand rvalue, boolean positive) {
        if (!positive) {
            filter.append("(!");
        }
        filter.append("(|");
        for (Literal value : (LiteralList) rvalue) {
            walkEq(lvalue, value);
        }
        filter.append(')');
        if (!positive) {
            filter.append(')');
        }
    }

    public void walkLike(Operand lvalue, Operand rvalue, boolean positive, boolean caseInsensitive) {
        if (!(rvalue instanceof StringLiteral)) {
            throw new QueryParseException("Invalid LIKE, right hand side must be a string: " + rvalue);
        }
        String like = ((StringLiteral) rvalue).value;
        if (caseInsensitive) {
            like = like.toLowerCase();
        }
        if (!positive) {
            filter.append("(!");
        }
        filter.append('(');
        walkReference(lvalue);
        filter.append('=');
        walkLikeWildcard(like);
        filter.append(')');
        if (!positive) {
            filter.append(')');
        }
    }

    /**
     * Turns a NXQL LIKE pattern into an LDAP wildcard.
     * <p>
     * % and _ are standard wildcards, and \ escapes them.
     */
    public void walkLikeWildcard(String like) {
        StringBuilder param = new StringBuilder();
        char[] chars = like.toCharArray();
        boolean escape = false;
        for (int i = 0; i < chars.length; i++) {
            char c = chars[i];
            boolean escapeNext = false;
            if (escape) {
                param.append(c);
            } else {
                switch(c) {
                    case '%':
                        if (param.length() != 0) {
                            addFilterParam(param.toString());
                            param.setLength(0);
                        }
                        filter.append('*');
                        break;
                    case // interpret it as an escaped _, not a wildcard
                    '_':
                        param.append(c);
                        break;
                    case '\\':
                        escapeNext = true;
                        break;
                    default:
                        param.append(c);
                        break;
                }
            }
            escape = escapeNext;
        }
        if (escape) {
            throw new QueryParseException("Invalid LIKE parameter ending with escape character");
        }
        if (param.length() != 0) {
            addFilterParam(param.toString());
        }
    }

    public void walkOperand(Operand operand) {
        if (operand instanceof Literal) {
            walkLiteral((Literal) operand);
        } else if (operand instanceof Function) {
            walkFunction((Function) operand);
        } else if (operand instanceof Expression) {
            walkExpression((Expression) operand);
        } else if (operand instanceof Reference) {
            walkReference((Reference) operand);
        } else {
            throw new QueryParseException("Unknown operand: " + operand);
        }
    }

    public void walkLiteral(Operand operand) {
        if (!(operand instanceof Literal)) {
            throw new QueryParseException("Requires literal instead of: " + operand);
        }
        Literal lit = (Literal) operand;
        if (lit instanceof BooleanLiteral) {
            walkBooleanLiteral((BooleanLiteral) lit);
        } else if (lit instanceof DateLiteral) {
            walkDateLiteral((DateLiteral) lit);
        } else if (lit instanceof DoubleLiteral) {
            walkDoubleLiteral((DoubleLiteral) lit);
        } else if (lit instanceof IntegerLiteral) {
            walkIntegerLiteral((IntegerLiteral) lit);
        } else if (lit instanceof StringLiteral) {
            walkStringLiteral((StringLiteral) lit);
        } else {
            throw new QueryParseException("Unknown literal: " + lit);
        }
    }

    public void walkBooleanLiteral(BooleanLiteral lit) {
        addFilterParam(Boolean.valueOf(lit.value));
    }

    public void walkDateLiteral(DateLiteral lit) {
        if (lit.onlyDate) {
            throw new QueryParseException("Cannot use only date in LDAP query: " + lit);
        }
        // let LDAP library serialize it
        addFilterParam(lit.toCalendar());
    }

    public void walkDoubleLiteral(DoubleLiteral lit) {
        addFilterParam(Double.valueOf(lit.value));
    }

    public void walkIntegerLiteral(IntegerLiteral lit) {
        addFilterParam(Long.valueOf(lit.value));
    }

    public void walkStringLiteral(StringLiteral lit)

    protected void addFilterParam(Serializable value) {
        filter.append('{');
        filter.append(paramIndex++);
        filter.append('}');
        params.add(value);
    }

    public Object walkFunction(Function func) {
        throw new QueryParseException(func.name);
    }

    public Field walkReference(Operand value) {
        if (!(value instanceof Reference)) {
            throw new QueryParseException("Invalid query, left hand side must be a property: " + value);
        }
        String name = ((Reference) value).name;
        if (directory.isReference(name)) {
            throw new QueryParseException("Column: " + name + " is a reference and cannot be queried for directory: " + directory.getName());
        }
        Field field = directory.getSchemaFieldMap().get(name);
        if (field == null) {
            throw new QueryParseException("No column: " + name + " for directory: " + directory.getName());
        }
        String backend = directory.getFieldMapper().getBackendField(name);
        filter.append(backend);
        return field;
    }
}


package org.nuxeo.ecm.directory.ldap;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import org.nuxeo.ecm.core.query.QueryParseException;
import org.nuxeo.ecm.core.query.sql.model.BooleanLiteral;
import org.nuxeo.ecm.core.query.sql.model.DateLiteral;
import org.nuxeo.ecm.core.query.sql.model.DoubleLiteral;
import org.nuxeo.ecm.core.query.sql.model.Expression;
import org.nuxeo.ecm.core.query.sql.model.Function;
import org.nuxeo.ecm.core.query.sql.model.IntegerLiteral;
import org.nuxeo.ecm.core.query.sql.model.Literal;
import org.nuxeo.ecm.core.query.sql.model.LiteralList;
import org.nuxeo.ecm.core.query.sql.model.MultiExpression;
import org.nuxeo.ecm.core.query.sql.model.Operand;
import org.nuxeo.ecm.core.query.sql.model.Operator;
import org.nuxeo.ecm.core.query.sql.model.Predicate;
import org.nuxeo.ecm.core.query.sql.model.Reference;
import org.nuxeo.ecm.core.query.sql.model.StringLiteral;
import org.nuxeo.ecm.core.schema.types.Field;
import org.nuxeo.ecm.core.schema.types.primitives.BooleanType;

/**
 * Creates an LDAP query filter from a Nuxeo Expression.
 *
 * @since 10.3
 */
public class LDAPFilterBuilder {

    protected static final String DATE_CAST = "DATE";

    protected final LDAPDirectory directory;

    public StringBuilder filter = new StringBuilder();

    public int paramIndex = 0;

    public final List<Serializable> params = new ArrayList<>();

    public LDAPFilterBuilder(LDAPDirectory directory) {
        this.directory = directory;
    }

    public void walk(Expression expression) {
        if (expression instanceof MultiExpression && ((MultiExpression) expression).predicates.isEmpty()) {
            // special-case empty query
            return;
        } else {
            walkExpression(expression);
        }
    }

    public void walkExpression(Expression expr) {
        Operator op = expr.operator;
        Operand lvalue = expr.lvalue;
        Operand rvalue = expr.rvalue;
        Reference ref = lvalue instanceof Reference ? (Reference) lvalue : null;
        String name = ref != null ? ref.name : null;
        String cast = ref != null ? ref.cast : null;
        if (DATE_CAST.equals(cast)) {
            checkDateLiteralForCast(op, rvalue, name);
        }
        if (op == Operator.SUM) {
            throw new QueryParseException("SUM");
        } else if (op == Operator.SUB) {
            throw new QueryParseException("SUB");
        } else if (op == Operator.MUL) {
            throw new QueryParseException("MUL");
        } else if (op == Operator.DIV) {
            throw new QueryParseException("DIV");
        } else if (op == Operator.LT) {
            walkLt(lvalue, rvalue);
        } else if (op == Operator.GT) {
            walkGt(lvalue, rvalue);
        } else if (op == Operator.EQ) {
            walkEq(lvalue, rvalue);
        } else if (op == Operator.NOTEQ) {
            walkNotEq(lvalue, rvalue);
        } else if (op == Operator.LTEQ) {
            walkLtEq(lvalue, rvalue);
        } else if (op == Operator.GTEQ) {
            walkGtEq(lvalue, rvalue);
        } else if (op == Operator.AND) {
            if (expr instanceof MultiExpression) {
                walkAndMultiExpression((MultiExpression) expr);
            } else {
                walkAnd(expr);
            }
        } else if (op == Operator.NOT) {
            walkNot(lvalue);
        } else if (op == Operator.OR) {
            if (expr instanceof MultiExpression) {
                walkOrMultiExpression((MultiExpression) expr);
            } else {
                walkOr(expr);
            }
        } else if (op == Operator.LIKE) {
            walkLike(lvalue, rvalue, true, false);
        } else if (op == Operator.ILIKE) {
            walkLike(lvalue, rvalue, true, true);
        } else if (op == Operator.NOTLIKE) {
            walkLike(lvalue, rvalue, false, false);
        } else if (op == Operator.NOTILIKE) {
            walkLike(lvalue, rvalue, false, true);
        } else if (op == Operator.IN) {
            walkIn(lvalue, rvalue, true);
        } else if (op == Operator.NOTIN) {
            walkIn(lvalue, rvalue, false);
        } else if (op == Operator.ISNULL) {
            walkIsNull(lvalue);
        } else if (op == Operator.ISNOTNULL) {
            walkIsNotNull(lvalue);
        } else if (op == Operator.BETWEEN) {
            walkBetween(lvalue, rvalue, true);
        } else if (op == Operator.NOTBETWEEN) {
            walkBetween(lvalue, rvalue, false);
        } else {
            throw new QueryParseException("Unknown operator: " + op);
        }
    }

    protected void checkDateLiteralForCast(Operator op, Operand value, String name) {
        if (op == Operator.BETWEEN || op == Operator.NOTBETWEEN) {
            LiteralList l = (LiteralList) value;
            checkDateLiteralForCast(l.get(0), name);
            checkDateLiteralForCast(l.get(1), name);
        } else {
            checkDateLiteralForCast(value, name);
        }
    }

    protected void checkDateLiteralForCast(Operand value, String name) {
        if (value instanceof DateLiteral && !((DateLiteral) value).onlyDate) {
            throw new QueryParseException("DATE() cast must be used with DATE literal, not TIMESTAMP: " + name);
        }
    }

    public void walkNot(Operand value) {
        filter.append("(!");
        walkOperand(value);
        filter.append(')');
    }

    public void walkIsNull(Operand value) {
        filter.append("(!");
        walkIsNotNull(value);
        filter.append(')');
    }

    public void walkIsNotNull(Operand value) {
        filter.append('(');
        walkReference(value);
        filter.append("=*)");
    }

    public void walkAndMultiExpression(MultiExpression expr) {
        walkMulti("&", expr.predicates);
    }

    public void walkAnd(Expression expr) {
        walkMulti("&", Arrays.asList(expr.lvalue, expr.rvalue));
    }

    public void walkOrMultiExpression(MultiExpression expr) {
        walkMulti("|", expr.predicates);
    }

    public void walkOr(Expression expr) {
        walkMulti("|", Arrays.asList(expr.lvalue, expr.rvalue));
    }

    protected void walkMulti(String op, List<? extends Operand> values) {
        if (values.size() == 1) {
            walkOperand(values.get(0));
        } else {
            filter.append('(');
            filter.append(op);
            for (Operand value : values) {
                walkOperand(value);
            }
            filter.append(')');
        }
    }

    public void walkEq(Operand lvalue, Operand rvalue) {
        walkBinOp("=", lvalue, rvalue);
    }

    public void walkNotEq(Operand lvalue, Operand rvalue) {
        filter.append("(!");
        walkEq(lvalue, rvalue);
        filter.append(')');
    }

    public void walkLt(Operand lvalue, Operand rvalue) {
        walkBinOp("<", lvalue, rvalue);
    }

    public void walkGt(Operand lvalue, Operand rvalue) {
        walkBinOp(">", lvalue, rvalue);
    }

    public void walkLtEq(Operand lvalue, Operand rvalue) {
        walkBinOp("<=", lvalue, rvalue);
    }

    public void walkGtEq(Operand lvalue, Operand rvalue) {
        walkBinOp(">=", lvalue, rvalue);
    }

    protected void walkBinOp(String op, Operand lvalue, Operand rvalue) {
        filter.append('(');
        Field field = walkReference(lvalue);
        filter.append(op);
        if (field.getType() instanceof BooleanType) {
            rvalue = makeBoolean(rvalue);
        }
        walkLiteral(rvalue);
        filter.append(')');
    }

    protected Operand makeBoolean(Operand rvalue) {
        if (rvalue instanceof BooleanLiteral) {
            return rvalue;
        }
        long v;
        if (!(rvalue instanceof IntegerLiteral) || ((v = ((IntegerLiteral) rvalue).value) != 0 && v != 1)) {
            throw new QueryParseException("Boolean expressions require boolean or literal 0 or 1 as right argument");
        }
        return new BooleanLiteral(v == 1);
    }

    public void walkBetween(Operand lvalue, Operand rvalue, boolean positive) {
        LiteralList list = (LiteralList) rvalue;
        Literal left = list.get(0);
        Literal right = list.get(1);
        if (!positive) {
            filter.append("(!");
        }
        filter.append("(&");
        walkGtEq(lvalue, left);
        walkLtEq(lvalue, right);
        filter.append(')');
        if (!positive) {
            filter.append(')');
        }
    }

    public void walkIn(Operand lvalue, Operand rvalue, boolean positive) {
        if (!positive) {
            filter.append("(!");
        }
        filter.append("(|");
        for (Literal value : (LiteralList) rvalue) {
            walkEq(lvalue, value);
        }
        filter.append(')');
        if (!positive) {
            filter.append(')');
        }
    }

    public void walkLike(Operand lvalue, Operand rvalue, boolean positive, boolean caseInsensitive) {
        if (!(rvalue instanceof StringLiteral)) {
            throw new QueryParseException("Invalid LIKE, right hand side must be a string: " + rvalue);
        }
        String like = ((StringLiteral) rvalue).value;
        if (caseInsensitive) {
            like = like.toLowerCase();
        }
        if (!positive) {
            filter.append("(!");
        }
        filter.append('(');
        walkR

        filter.append('=');
        walkLikeWildcard(like);
        filter.append(')');
        if (!positive) {
            filter.append(')');
        }
    }

    /**
     * Turns a NXQL LIKE pattern into an LDAP wildcard.
     * <p>
     * % and _ are standard wildcards, and \ escapes them.
     */
    public void walkLikeWildcard(String like) {
        StringBuilder param = new StringBuilder();
        char[] chars = like.toCharArray();
        boolean escape = false;
        for (int i = 0; i < chars.length; i++) {
            char c = chars[i];
            boolean escapeNext = false;
            if (escape) {
                param.append(c);
            } else {
                switch(c) {
                    case '%':
                        if (param.length() != 0) {
                            addFilterParam(param.toString());
                            param.setLength(0);
                        }
                        filter.append('*');
                        break;
                    case // interpret it as an escaped _, not a wildcard
                    '_':
                        param.append(c);
                        break;
                    case '\\':
                        escapeNext = true;
                        break;
                    default:
                        param.append(c);
                        break;
                }
            }
            escape = escapeNext;
        }
        if (escape) {
            throw new QueryParseException("Invalid LIKE parameter ending with escape character");
        }
        if (param.length() != 0) {
            addFilterParam(param.toString());
        }
    }

    public void walkOperand(Operand operand) {
        if (operand instanceof Literal) {
            walkLiteral((Literal) operand);
        } else if (operand instanceof Function) {
            walkFunction((Function) operand);
        } else if (operand instanceof Expression) {
            walkExpression((Expression) operand);
        } else if (operand instanceof Reference) {
            walkReference((Reference) operand);
        } else {
            throw new QueryParseException("Unknown operand: " + operand);
        }
    }

    public void walkLiteral(Operand operand) {
        if (!(operand instanceof Literal)) {
            throw new QueryParseException("Requires literal instead of: " + operand);
        }
        Literal lit = (Literal) operand;
        if (lit instanceof BooleanLiteral) {
            walkBooleanLiteral((BooleanLiteral) lit);
        } else if (lit instanceof DateLiteral) {
            walkDateLiteral((DateLiteral) lit);
        } else if (lit instanceof DoubleLiteral) {
            walkDoubleLiteral((DoubleLiteral) lit);
        } else if (lit instanceof IntegerLiteral) {
            walkIntegerLiteral((IntegerLiteral) lit);
        } else if (lit instanceof StringLiteral) {
            walkStringLiteral((StringLiteral) lit);
        } else {
            throw new QueryParseException("Unknown literal: " + lit);
        }
    }

    public void walkBooleanLiteral(BooleanLiteral lit) {
        addFilterParam(Boolean.valueOf(lit.value));
    }

    public void walkDateLiteral(DateLiteral lit) {
        if (lit.onlyDate) {
            throw new QueryParseException("Cannot use only date in LDAP query: " + lit);
        }
        // let LDAP library serialize it
        addFilterParam(lit.toCalendar());
    }

    public void walkDoubleLiteral(DoubleLiteral lit) {
        addFilterParam(Double.valueOf(lit.value));
    }

    public void walkIntegerLiteral(IntegerLiteral lit) {
        addFilterParam(Long.valueOf(lit.value));
    }

    public void walkStringLiteral(StringLiteral lit) {
        addFilterParam(lit.value);
    }

    protected void addFilterParam(Serializable value) {
        filter.append('{');
        filter.append(paramIndex++);
        filter.append('}');
        params.add(value);
    }

    public Object walkFunction(Function func) {
        throw new QueryParseException(func.name);
    }

    public Field walkReference(Operand value) {
        if (!(value instanceof Reference)) {
            throw new QueryParseException("Invalid query, left hand side must be a property: " + value);
        }
        String name = ((Reference) value).name;
        if (directory.isReference(name)) {
            throw new QueryParseException("Column: " + name + " is a reference and cannot be queried for directory: " + directory.getName());
        }
        Field field = directory.getSchemaFieldMap().get(name);
        if (field == null) {
            throw new QueryParseException("No column: " + name + " for directory: " + directory.getName());
        }
        String backend = directory.getFieldMapper().getBackendField(name);
        filter.append(backend);
        return field;
    }
}


package org.orekit.time;

/**
 * TAI UTC offset model.
 * @see UTCTAIOffsetsLoader
 * @author Luc Maisonobe
 * @since 7.1
 */
public class OffsetModel {

    /**
     * Date of the offset start.
     */
    private final DateComponents start;

    /**
     * Reference date of the linear model as a modified julian day.
     */
    private final int mjdRef;

    /**
     * Offset at reference date in seconds (TAI minus UTC).
     */
    private final double offset;

    /**
     * Offset slope in seconds per UTC day (TAI minus UTC / dUTC).
     */
    private final double slope;

    /**
     * Constructor for a linear offset model.
     *

     * These models were used prior to 1972.
     *

     * @param start date of the offset start
     * @param mjdRef reference date of the linear model as a modified julian day
     * @param offset offset at reference date in seconds (TAI minus UTC)
     * @param slope offset slope in seconds per UTC day (TAI minus UTC / dUTC)
     */
    public OffsetModel(final DateComponents start, final int mjdRef, final double offset, final double slope) {
        this.start = start;
        this.mjdRef = mjdRef;
        this.offset = offset;
        this.slope = slope;
    }

    /**
     * Constructor for a constant offset model.
     *

     * These models are used since 1972.
     *

     * @param start date of the offset start
     * @param offset offset at reference date in seconds (TAI minus UTC)
     */
    public OffsetModel(final DateComponents start, final int offset) {
        this(start, 41317, offset, 0.0);
    }

    /**
     * Get the date of the offset start.
     * @return date of the offset start
     */
    public DateComponents getStart() {
        return start;
    }

    /**
     * Get the reference date of the linear model as a modified julian day.
     * @return reference date of the linear model as a modified julian day
     */
    public int getMJDRef() {
        return mjdRef;
    }

    /**
     * Offset at reference date in seconds (TAI minus UTC).
     * @return offset at reference date in seconds (TAI minus UTC)
     */
    public double getOffset() {
        return offset;
    }

    /**
     * Offset slope in seconds per UTC day (TAI minus UTC / dUTC).
     * @return offset slope in seconds per UTC day (TAI minus UTC / dUTC)
     */


package org.orekit.time;

/**
 * TAI UTC offset model.
 * @see UTCTAIOffsetsLoader
 * @author Luc Maisonobe
 * @since 7.1
 */
public class OffsetModel {

    /**
     * Date of the offset start.
     */
    private final DateComponents start;

    /**
     * Reference date of the linear model as a modified julian day.
     */
    private final int mjdRef;

    /**
     * Offset at reference date in seconds (TAI minus UTC).
     */
    private final double offset;

    /**
     * Offset slope in seconds per UTC day (TAI minus UTC / dUTC).
     */
    private final double slope;

    /**
     * Constructor for a linear offset model.
     *

     * These models were used prior to 1972.
     *

     * @param start date of the offset start
     * @param mjdRef reference date of the linear model as a modified julian day
     * @param offset offset at reference date in seconds (TAI minus UTC)
     * @param slope offset slope in seconds per UTC day (TAI minus UTC / dUTC)
     */
    public OffsetModel(final DateComponents start, final int mjdRef, final double offset, final double slope) {
        this.start = start;
        this.mjdRef = mjdRef;
        this.offset = offset;
        this.slope = slope;
    }

    /**
     * Constructor for a constant offset model.
     *

     * These models are used since 1972.
     *

     * @param start date of the offset start
     * @param offset offset at reference date in seconds (TAI minus UTC)
     */
    public OffsetModel(final DateComponents start, final int offset) {
        this(start, 41317, offset, 0.0);
    }

    /**
     * Get the date of the offset start.
     * @return date of the offset start
     */
    public DateComponents getStart()

    /**
     * Get the reference date of the linear model as a modified julian day.
     * @return reference date of the linear model as a modified julian day
     */
    public int getMJDRef() {
        return mjdRef;
    }

    /**
     * Offset at reference date in seconds (TAI minus UTC).
     * @return offset at reference date in seconds (TAI minus UTC)
     */
    public double getOffset() {
        return offset;
    }

    /**
     * Offset slope in seconds per UTC day (TAI minus UTC / dUTC).
     * @return offset slope in seconds per UTC day (TAI minus UTC / dUTC)
     */
    public double getSlope() {
        return slope;
    }
}


package org.orekit.time;

/**
 * TAI UTC offset model.
 * @see UTCTAIOffsetsLoader
 * @author Luc Maisonobe
 * @since 7.1
 */
public class OffsetModel {

    /**
     * Date of the offset start.
     */
    private final DateComponents start;

    /**
     * Reference date of the linear model as a modified julian day.
     */
    private final int mjdRef;

    /**
     * Offset at reference date in seconds (TAI minus UTC).
     */
    private final double offset;

    /**
     * Offset slope in seconds per UTC day (TAI minus UTC / dUTC).
     */
    private final double slope;

    /**
     * Constructor for a linear offset model.
     *

     * These models were used prior to 1972.
     *

     * @param start date of the offset start
     * @param mjdRef reference date of the linear model as a modified julian day
     * @param offset offset at reference date in seconds (TAI minus UTC)
     * @param slope offset slope in seconds per UTC day (TAI minus UTC / dUTC)
     */
    public OffsetModel(final DateComponents start, final int mjdRef, final double offset, final double slope) {
        this.start = start;
        this.mjdRef = mjdRef;
        this.offset = offset;
        this.slope = slope;
    }

    /**
     * Constructor for a constant offset model.
     *

     * These models are used since 1972.
     *

     * @param start date of the offset start
     * @param offset offset at reference date in seconds (TAI minus UTC)
     */
    public OffsetModel(final DateComponents start, final int offset) {
        this(start, 41317, offset, 0.0);
    }

    /**
     * Get the date of the offset start.
     * @return date of the offset start
     */
    public DateComponents getStart() {
        return start;
    }

    /**
     * Get the reference date of the linear model as a modified julian day.
     * @return reference date of the linear model as a modified julian day
     */
    public int getMJDRef() {
        ret

    }

    /**
     * Offset at reference date in seconds (TAI minus UTC).
     * @return offset at reference date in seconds (TAI minus UTC)
     */
    public double getOffset() {
        return offset;
    }

    /**
     * Offset slope in seconds per UTC day (TAI minus UTC / dUTC).
     * @return offset slope in seconds per UTC day (TAI minus UTC / dUTC)
     */
    public double getSlope() {
        return slope;
    }
}


public int getMJDRef() {
        return mjdRef;
    }

package org.orekit.time;

/**
 * TAI UTC offset model.
 * @see UTCTAIOffsetsLoader
 * @author Luc Maisonobe
 * @since 7.1
 */
public class OffsetModel {

    /**
     * Date of the offset start.
     */
    private final DateComponents start;

    /**
     * Reference date of the linear model as a modified julian day.
     */
    private final int mjdRef;

    /**
     * Offset at reference date in seconds (TAI minus UTC).
     */
    private final double offset;

    /**
     * Offset slope in seconds per UTC day (TAI minus UTC / dUTC).
     */
    private final double slope;

    /**
     * Constructor for a linear offset model.
     *

     * These models were used prior to 1972.
     *

     * @param start date of the offset start
     * @param mjdRef reference date of the linear model as a modified julian day
     * @param offset offset at reference date in seconds (TAI minus UTC)
     * @param slope offset slope in seconds per UTC day (TAI minus UTC / dUTC)
     */
    public OffsetModel(final DateComponents start, final int mjdRef, final double offset, final double slope) {
        this.start = start;
        this.mjdRef = mjdRef;
        this.offset = offset;
        this.slope = slope;
    }

    /**
     * Constructor for a constant offset model.
     *

     * These models are used since 1972.
     *

     * @param start date of the offset start
     * @param offset offset at reference date in seconds (TAI minus UTC)
     */
    public OffsetModel(final DateComponents start, final int offset) {
        this(start, 41317, offset, 0.0);
    }

    /**
     * Get the date of the offset start.
     * @return date of the offset start
     */
    public DateComponents getStart() {
        return start;
    }

    /**
     * Get the reference date of the linear model as a modified julian day.
     * @return reference date of the linear model as a modified julian day
     */

    /**
     * Offset at reference date in seconds (TAI minus UTC).
     * @return offset at reference date in seconds (TAI minus UTC)
     */
    public double getOffset() {
        return offset;
    }

    /**
     * Offset slope in seconds per UTC day (TAI minus UTC / dUTC).
     * @return offset slope in seconds per UTC day (TAI minus UTC / dUTC)
     */
    public double getSlope() {
        return slope;
    }
}


public boolean onTransact(int code, Parcel data, Parcel reply, int flags) throws RemoteException

package com.huawei.servicehost.normal;

import android.os.Binder;
import android.os.IBinder;
import android.os.IInterface;
import android.os.Parcel;
import android.os.RemoteException;

public interface IIPEvent4Result extends IInterface {

    public static abstract class Stub extends Binder implements IIPEvent4Result {

        private static final String DESCRIPTOR = "com.huawei.servicehost.normal.IIPEvent4Result";

        private static class Proxy implements IIPEvent4Result {

            private IBinder mRemote;

            Proxy(IBinder remote) {
                this.mRemote = remote;
            }

            public IBinder asBinder() {
                return this.mRemote;
            }

            public String getInterfaceDescriptor() {
                return Stub.DESCRIPTOR;
            }
        }

        public Stub() {
            attachInterface(this, DESCRIPTOR);
        }

        public static IIPEvent4Result asInterface(IBinder obj) {
            if (obj == null) {
                return null;
            }
            IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
            if (iin == null || !(iin instanceof IIPEvent4Result)) {
                return new Proxy(obj);
            }
            return (IIPEvent4Result) iin;
        }

        public IBinder asBinder() {
            return this;
        }

{
            String descriptor = DESCRIPTOR;
            if (code != 1598968902) {
                return super.onTransact(code, data, reply, flags);
            }
            reply.writeString(descriptor);
            return true;
        }
    }
}


{
                return this.mRemote;
            }

package com.huawei.servicehost.normal;

import android.os.Binder;
import android.os.IBinder;
import android.os.IInterface;
import android.os.Parcel;
import android.os.RemoteException;

public interface IIPEvent4Result extends IInterface {

    public static abstract class Stub extends Binder implements IIPEvent4Result {

        private static final String DESCRIPTOR = "com.huawei.servicehost.normal.IIPEvent4Result";

        private static class Proxy implements IIPEvent4Result {

            private IBinder mRemote;

            Proxy(IBinder remote) {
                this.mRemote = remote;
            }

            public IBinder asBinder()

            public String getInterfaceDescriptor() {
                return Stub.DESCRIPTOR;
            }
        }

        public Stub() {
            attachInterface(this, DESCRIPTOR);
        }

        public static IIPEvent4Result asInterface(IBinder obj) {
            if (obj == null) {
                return null;
            }
            IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
            if (iin == null || !(iin instanceof IIPEvent4Result)) {
                return new Proxy(obj);
            }
            return (IIPEvent4Result) iin;
        }

        public IBinder asBinder() {
            return this;
        }

        public boolean onTransact(int code, Parcel data, Parcel reply, int flags) throws RemoteException {
            String descriptor = DESCRIPTOR;
            if (code != 1598968902) {
                return super.onTransact(code, data, reply, flags);
            }
            reply.writeString(descriptor);
            return true;
        }
    }
}


package com.huawei.servicehost.normal;

import android.os.Binder;
import android.os.IBinder;
import android.os.IInterface;
import android.os.Parcel;
import android.os.RemoteException;

public interface IIPEvent4Result extends IInterface {

    public static abstract class Stub extends Binder implements IIPEvent4Result {

        private static final String DESCRIPTOR = "com.huawei.servicehost.normal.IIPEvent4Result";

        private static class Proxy implements IIPEvent4Result {

            private IBinder mRemote;

            Proxy(IBinder remote) {
                this.mRemote = remote;
            }

            public IBinder asBinder() {
                return

            }

            public String getInterfaceDescriptor() {
                return Stub.DESCRIPTOR;
            }
        }

        public Stub() {
            attachInterface(this, DESCRIPTOR);
        }

        public static IIPEvent4Result asInterface(IBinder obj) {
            if (obj == null) {
                return null;
            }
            IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
            if (iin == null || !(iin instanceof IIPEvent4Result)) {
                return new Proxy(obj);
            }
            return (IIPEvent4Result) iin;
        }

        public IBinder asBinder() {
            return this;
        }

        public boolean onTransact(int code, Parcel data, Parcel reply, int flags) throws RemoteException {
            String descriptor = DESCRIPTOR;
            if (code != 1598968902) {
                return super.onTransact(code, data, reply, flags);
            }
            reply.writeString(descriptor);
            return true;
        }
    }
}