Commit 9616b616 authored by Philip Makedonski's avatar Philip Makedonski
Browse files

Merge branch 'dev' into 'master'

+ added JsonSchemaBridge to handle ASN.1 files and generated JSON schemas #29, fixes for handling union, nested, and sub- types #8, #21, check for union template specification #31

See merge request swe/tools/t3tools/t3q!8
parents ced71b28 a54dc940
Loading
Loading
Loading
Loading
+17 −7
Original line number Diff line number Diff line
@@ -2,13 +2,15 @@
  <ConfigurationProfiles>
    <QualityCheckProfile>
      <profileName>stf160Profile</profileName>
      <profileVersion>v2.1.0b3</profileVersion>
      <profileVersion>v2.1.0b4</profileVersion>
      <!--  <resourceExtensionsRegExp>ttcn|ttcn3|3mp</resourceExtensionsRegExp> -->
      <!--    <projectExtension>t3p</projectExtension> -->
      <ignoredResourceRegExp>((.*[/\\]Common[/\\](IMS_LibSip|IMS_XSD)[/\\].*[.]ttcn)|(.*[/\\]Common[/\\](HTTP)[/\\]uri.*[.]ttcn)|(.*[/\\]LTE_A_R12[/\\](D2D_ProSe)[/\\]urn.*[.]ttcn)|(.*[/\\]IMS[/\\]XCAP_XSD[/\\].*[.]ttcn)|(.*[/\\]MCX[/\\]CommonXSD[/\\].*[.]ttcn)|(.*[/\\].*[/\\][Cc]ommon[/\\]TestcaseProperties.*[.]ttcn))</ignoredResourceRegExp>   
      <!-- added pattern for files generated from ASN.1 -->
      <ignoredResourceRegExp>((.*asn[.]json[.].*ttcn)|(.*[/\\]Common[/\\](IMS_LibSip|IMS_XSD)[/\\].*[.]ttcn)|(.*[/\\]Common[/\\](HTTP)[/\\]uri.*[.]ttcn)|(.*[/\\]LTE_A_R12[/\\](D2D_ProSe)[/\\]urn.*[.]ttcn)|(.*[/\\]IMS[/\\]XCAP_XSD[/\\].*[.]ttcn)|(.*[/\\]MCX[/\\]CommonXSD[/\\].*[.]ttcn)|(.*[/\\].*[/\\][Cc]ommon[/\\]TestcaseProperties.*[.]ttcn))</ignoredResourceRegExp>   
      <!--   <settingRecursiveProcessing>true</settingRecursiveProcessing>  -->
      <checkNoUninitializedFieldsInTemplates>true</checkNoUninitializedFieldsInTemplates>
      <checkNoUninitializedFieldsInTemplatesRecursion>false</checkNoUninitializedFieldsInTemplatesRecursion>
      <checkNoUninitializedFieldsInTemplatesRecursion>true</checkNoUninitializedFieldsInTemplatesRecursion>
      <checkNoZeroOrMultipleFieldsInUnionTemplates>false</checkNoZeroOrMultipleFieldsInUnionTemplates>
      <checkNoUninitialisedVariables>false</checkNoUninitialisedVariables>
      <checkNoUninitialisedVariablesExclude>  <!--  to be discarded if checkNoUninitialisedVariables is true. If list is empty, no restrictions   -->
        <string>enumerated</string>
@@ -123,6 +125,8 @@
      </namingConventionsConfig>
      <dependencyOutputPath>DOCUMENTATION</dependencyOutputPath>
      <pathFormattedOutputPath>FORMATTED</pathFormattedOutputPath>
      <titanCompilerPath>compiler</titanCompilerPath>      
      <jsonSchemaPath></jsonSchemaPath>
      <!-- formattingParameters>
        <tabs>false</tabs>
        <unixNewline>false</unixNewline>
@@ -145,8 +149,8 @@
    </QualityCheckProfile>
    <QualityCheckProfile>
      <profileName>defaultProfile</profileName>
      <profileVersion>v2.1.0b3</profileVersion>
      <ignoredResourceRegExp>(.*[/\\]Common[/\\](IMS_LibSip|IMS_XSD)[/\\].*[.]ttcn)</ignoredResourceRegExp>
      <profileVersion>v2.1.0b4</profileVersion>
      <ignoredResourceRegExp>(.*asn[.]json[.].*ttcn)|(.*[/\\]Common[/\\](IMS_LibSip|IMS_XSD)[/\\].*[.]ttcn)</ignoredResourceRegExp>
      <settingAbortOnError>true</settingAbortOnError>
      <loggingConfiguration>
        <showFullPath>false</showFullPath>
@@ -201,6 +205,7 @@
      <checkNoUnusedLocalDefinitions>true</checkNoUnusedLocalDefinitions>
      <checkNoUninitializedFieldsInTemplates>true</checkNoUninitializedFieldsInTemplates>
      <checkNoUninitializedFieldsInTemplatesRecursion>false</checkNoUninitializedFieldsInTemplatesRecursion>
      <checkNoZeroOrMultipleFieldsInUnionTemplates>false</checkNoZeroOrMultipleFieldsInUnionTemplates>
      <checkNoUninitialisedVariables>true</checkNoUninitialisedVariables>
      <checkNoUninitialisedVariablesExclude>
        <string>enumerated</string>
@@ -263,11 +268,13 @@
        <enumeratedValueRegExp>e_[a-z].*</enumeratedValueRegExp>
      </namingConventionsConfig>
      <pathFormattedOutputPath>FORMATTED</pathFormattedOutputPath>
      <titanCompilerPath>compiler</titanCompilerPath>
      <jsonSchemaPath></jsonSchemaPath>
    </QualityCheckProfile>
    <QualityCheckProfile>
      <profileName>nothing</profileName>
      <profileVersion>v2.1.0b3</profileVersion>
      <ignoredResourceRegExp>(.*[/\\]Common[/\\](IMS_LibSip|IMS_XSD)[/\\].*[.]ttcn)</ignoredResourceRegExp>
      <profileVersion>v2.1.0b4</profileVersion>
      <ignoredResourceRegExp>(.*asn[.]json[.].*ttcn)|(.*[/\\]Common[/\\](IMS_LibSip|IMS_XSD)[/\\].*[.]ttcn)</ignoredResourceRegExp>
      <settingAbortOnError>true</settingAbortOnError>
      <loggingConfiguration>
        <showFullPath>false</showFullPath>
@@ -320,6 +327,7 @@
      <checkNoUnusedLocalDefinitions>false</checkNoUnusedLocalDefinitions>
      <checkNoUninitializedFieldsInTemplates>true</checkNoUninitializedFieldsInTemplates>
      <checkNoUninitializedFieldsInTemplatesRecursion>false</checkNoUninitializedFieldsInTemplatesRecursion>
      <checkNoZeroOrMultipleFieldsInUnionTemplates>false</checkNoZeroOrMultipleFieldsInUnionTemplates>
      <checkNoUninitialisedVariables>true</checkNoUninitialisedVariables>
      <checkNoUninitialisedVariablesExclude>
        <string>enumerated</string>
@@ -382,6 +390,8 @@
        <enumeratedValueRegExp>e_[a-z].*</enumeratedValueRegExp>
      </namingConventionsConfig>
      <pathFormattedOutputPath>FORMATTED</pathFormattedOutputPath>
      <titanCompilerPath>compiler</titanCompilerPath>      
      <jsonSchemaPath></jsonSchemaPath>
    </QualityCheckProfile>    
  </ConfigurationProfiles>
  <defaultConfigurationProfile>all</defaultConfigurationProfile>
+16 −6
Original line number Diff line number Diff line
@@ -2,13 +2,15 @@
  <ConfigurationProfiles>
    <QualityCheckProfile>
      <profileName>stf160Profile</profileName>
      <profileVersion>v2.1.0b3</profileVersion>
      <profileVersion>v2.1.0b4</profileVersion>
      <!--  <resourceExtensionsRegExp>ttcn|ttcn3|3mp</resourceExtensionsRegExp> -->
      <!--    <projectExtension>t3p</projectExtension> -->
      <ignoredResourceRegExp>((.*[/\\]Common[/\\](IMS_LibSip|IMS_XSD)[/\\].*[.]ttcn)|(.*[/\\]Common[/\\](HTTP)[/\\]uri.*[.]ttcn)|(.*[/\\]LTE_A_R12[/\\](D2D_ProSe)[/\\]urn.*[.]ttcn)|(.*[/\\]IMS[/\\]XCAP_XSD[/\\].*[.]ttcn)|(.*[/\\]MCX[/\\]CommonXSD[/\\].*[.]ttcn)|(.*[/\\].*[/\\][Cc]ommon[/\\]TestcaseProperties.*[.]ttcn))</ignoredResourceRegExp>   
      <!-- added pattern for files generated from ASN.1 -->
      <ignoredResourceRegExp>((.*asn[.]json[.].*[.]ttcn)|(.*[/\\]Common[/\\](IMS_LibSip|IMS_XSD)[/\\].*[.]ttcn)|(.*[/\\]Common[/\\](HTTP)[/\\]uri.*[.]ttcn)|(.*[/\\]LTE_A_R12[/\\](D2D_ProSe)[/\\]urn.*[.]ttcn)|(.*[/\\]IMS[/\\]XCAP_XSD[/\\].*[.]ttcn)|(.*[/\\]MCX[/\\]CommonXSD[/\\].*[.]ttcn)|(.*[/\\].*[/\\][Cc]ommon[/\\]TestcaseProperties.*[.]ttcn))</ignoredResourceRegExp>   
      <!--   <settingRecursiveProcessing>true</settingRecursiveProcessing>  -->
      <checkNoUninitializedFieldsInTemplates>false</checkNoUninitializedFieldsInTemplates>
      <checkNoUninitializedFieldsInTemplatesRecursion>false</checkNoUninitializedFieldsInTemplatesRecursion>
      <checkNoZeroOrMultipleFieldsInUnionTemplates>false</checkNoZeroOrMultipleFieldsInUnionTemplates>
      <checkNoUninitialisedVariables>false</checkNoUninitialisedVariables>
      <checkNoUninitialisedVariablesExclude>  <!--  to be discarded if checkNoUninitialisedVariables is true. If list is empty, no restrictions   -->
        <string>enumerated</string>
@@ -123,6 +125,8 @@
      </namingConventionsConfig>
      <dependencyOutputPath>DOCUMENTATION</dependencyOutputPath>
      <pathFormattedOutputPath>FORMATTED</pathFormattedOutputPath>
      <titanCompilerPath>./compiler</titanCompilerPath>
      <jsonSchemaPath></jsonSchemaPath>
      <!-- formattingParameters>
        <tabs>false</tabs>
        <unixNewline>false</unixNewline>
@@ -145,8 +149,8 @@
    </QualityCheckProfile>
    <QualityCheckProfile>
      <profileName>defaultProfile</profileName>
      <profileVersion>v2.1.0b3</profileVersion>
      <ignoredResourceRegExp>(.*[/\\]Common[/\\](IMS_LibSip|IMS_XSD)[/\\].*[.]ttcn)</ignoredResourceRegExp>
      <profileVersion>v2.1.0b4</profileVersion>
      <ignoredResourceRegExp>(.*asn[.]json[.].*ttcn)|(.*[/\\]Common[/\\](IMS_LibSip|IMS_XSD)[/\\].*[.]ttcn)</ignoredResourceRegExp>
      <settingAbortOnError>true</settingAbortOnError>
      <loggingConfiguration>
        <showFullPath>false</showFullPath>
@@ -201,6 +205,7 @@
      <checkNoUnusedLocalDefinitions>true</checkNoUnusedLocalDefinitions>
      <checkNoUninitializedFieldsInTemplates>false</checkNoUninitializedFieldsInTemplates>
      <checkNoUninitializedFieldsInTemplatesRecursion>false</checkNoUninitializedFieldsInTemplatesRecursion>
      <checkNoZeroOrMultipleFieldsInUnionTemplates>false</checkNoZeroOrMultipleFieldsInUnionTemplates>
      <checkNoUninitialisedVariables>true</checkNoUninitialisedVariables>
      <checkNoUninitialisedVariablesExclude>
        <string>enumerated</string>
@@ -263,11 +268,13 @@
        <enumeratedValueRegExp>e_[a-z].*</enumeratedValueRegExp>
      </namingConventionsConfig>
      <pathFormattedOutputPath>FORMATTED</pathFormattedOutputPath>
      <titanCompilerPath>compiler</titanCompilerPath>      
      <jsonSchemaPath></jsonSchemaPath>
    </QualityCheckProfile>
    <QualityCheckProfile>
      <profileName>nothing</profileName>
      <profileVersion>v2.1.0b3</profileVersion>
      <ignoredResourceRegExp>(.*[/\\]Common[/\\](IMS_LibSip|IMS_XSD)[/\\].*[.]ttcn)</ignoredResourceRegExp>
      <profileVersion>v2.1.0b4</profileVersion>
      <ignoredResourceRegExp>(.*asn[.]json[.].*ttcn)|(.*[/\\]Common[/\\](IMS_LibSip|IMS_XSD)[/\\].*[.]ttcn)</ignoredResourceRegExp>
      <settingAbortOnError>true</settingAbortOnError>
      <loggingConfiguration>
        <showFullPath>false</showFullPath>
@@ -320,6 +327,7 @@
      <checkNoUnusedLocalDefinitions>false</checkNoUnusedLocalDefinitions>
      <checkNoUninitializedFieldsInTemplates>false</checkNoUninitializedFieldsInTemplates>
      <checkNoUninitializedFieldsInTemplatesRecursion>false</checkNoUninitializedFieldsInTemplatesRecursion>
      <checkNoZeroOrMultipleFieldsInUnionTemplates>false</checkNoZeroOrMultipleFieldsInUnionTemplates>
      <checkNoUninitialisedVariables>true</checkNoUninitialisedVariables>
      <checkNoUninitialisedVariablesExclude>
        <string>enumerated</string>
@@ -382,6 +390,8 @@
        <enumeratedValueRegExp>e_[a-z].*</enumeratedValueRegExp>
      </namingConventionsConfig>
      <pathFormattedOutputPath>FORMATTED</pathFormattedOutputPath>
      <titanCompilerPath>compiler</titanCompilerPath>
      <jsonSchemaPath></jsonSchemaPath>            
    </QualityCheckProfile>    
  </ConfigurationProfiles>
  <defaultConfigurationProfile>all</defaultConfigurationProfile>
+8 −0
Original line number Diff line number Diff line
@@ -8,12 +8,14 @@ import org.eclipse.emf.ecore.resource.Resource;
import org.eclipse.emf.ecore.resource.Resource.Diagnostic;
import org.eclipse.emf.ecore.util.Diagnostician;
import org.eclipse.emf.ecore.util.EcoreUtil;
import org.eclipse.xtext.EcoreUtil2;
import org.eclipse.xtext.validation.FeatureBasedDiagnostic;

import com.google.common.base.Stopwatch;

import de.ugoe.cs.swe.common.MiscTools;
import de.ugoe.cs.swe.common.logging.LoggingInterface;
import de.ugoe.cs.swe.common.logging.LoggingInterface.LogLevel;
import de.ugoe.cs.swe.common.logging.LoggingInterface.MessageClass;
import de.ugoe.cs.swe.validation.TTCN3StatisticsProvider;

@@ -36,6 +38,12 @@ public class Analyzer implements Callable<TTCN3Output> {

		// validate the resource
		EcoreUtil.resolveAll(this.resource);
		if (T3Q.getLogLevel() == LogLevel.DEBUG) {
			System.out.println("Resolving references: " + this.resource.getURI().devicePath().replaceFirst("///", "") + '\n'
					+ "       ...done in " + stopwatch.elapsed(TimeUnit.MILLISECONDS) + "ms ("
					+ MiscTools.secondsToString(stopwatch.elapsed(TimeUnit.SECONDS)) + " minutes).");
		}

		EObject model = this.resource.getContents().get(0);
		org.eclipse.emf.common.util.Diagnostic diagnostic = null;
		diagnostic = Diagnostician.INSTANCE.validate(model);
+221 −0
Original line number Diff line number Diff line
package de.ugoe.cs.swe.T3Q;
import java.io.*;
import java.net.*;
import java.nio.charset.StandardCharsets;
import java.nio.file.*;
import java.util.*;

import de.ugoe.cs.swe.common.logging.LoggingInterface.LogLevel;

public class HttpFileClient {
    
    private static final String CRLF = "\r\n";
    private static final String BOUNDARY = "----WebKitFormBoundary" + System.currentTimeMillis();
    
    /**
     * Response container holding the JSON data and additional metadata
     */
    public static class ApiResponse {
        private final String jsonBody;
        private final int statusCode;
        private final Map<String, List<String>> headers;
        
        public ApiResponse(String jsonBody, int statusCode, Map<String, List<String>> headers) {
            this.jsonBody = jsonBody;
            this.statusCode = statusCode;
            this.headers = headers;
        }
        
        public String getJsonBody() { return jsonBody; }
        public int getStatusCode() { return statusCode; }
        public Map<String, List<String>> getHeaders() { return headers; }
        public String getHeader(String name) {
            List<String> values = headers.get(name);
            return values != null && !values.isEmpty() ? values.get(0) : null;
        }
    }
    
    /**
     * Upload one or more files via POST to the specified URL
     * 
     * @param url API endpoint URL
     * @param files Map of field names to file paths
     * @param additionalFields Optional text fields to include in the request
     * @return ApiResponse containing JSON and metadata
     */
    public static ApiResponse uploadFiles(String url, Map<String, Path> files, 
                                         Map<String, String> additionalFields) throws IOException {
        log("CLIENT: Starting upload to " + url);
        URL apiUrl = new URL(url);
        HttpURLConnection conn = (HttpURLConnection) apiUrl.openConnection();
        
        try {
            // Configure connection
            log("CLIENT: Configuring connection");
            conn.setRequestMethod("POST");
            conn.setDoOutput(true);
            conn.setDoInput(true);
            conn.setUseCaches(false);
            conn.setRequestProperty("Content-Type", "multipart/form-data; boundary=" + BOUNDARY);
            conn.setRequestProperty("Accept", "application/json");
            conn.setRequestProperty("Connection", "Keep-Alive");
            conn.setChunkedStreamingMode(8192); // Use chunked mode to avoid hanging
            
            log("CLIENT: Getting output stream");
            // Write multipart request body
            try (OutputStream out = conn.getOutputStream()) {
                log("CLIENT: Got output stream, writing data");
                
                // Add additional text fields if provided
                if (additionalFields != null) {
                    for (Map.Entry<String, String> field : additionalFields.entrySet()) {
                        log("CLIENT: Writing field: " + field.getKey());
                        writeField(out, field.getKey(), field.getValue());
                    }
                }
                
                // Add files
                for (Map.Entry<String, Path> file : files.entrySet()) {
                    log("CLIENT: Writing file: " + file.getValue().getFileName());
                    writeFile(out, file.getKey(), file.getValue());
                }
                
                // End multipart request
                log("CLIENT: Writing end boundary");
                String endBoundary = "--" + BOUNDARY + "--" + CRLF;
                out.write(endBoundary.getBytes(StandardCharsets.UTF_8));
                out.flush();
                log("CLIENT: Finished writing request body");
            }
            
            // Read response
            log("CLIENT: Getting response code");
            int statusCode = conn.getResponseCode();
            log("CLIENT: Response code: " + statusCode);
            InputStream responseStream = statusCode >= 400 ? conn.getErrorStream() : conn.getInputStream();
            
            String jsonResponse = readInputStream(responseStream);
//            log("CLIENT: Got response: " + jsonResponse);
            Map<String, List<String>> headers = conn.getHeaderFields();
            
            return new ApiResponse(jsonResponse, statusCode, headers);
            
        } finally {
            conn.disconnect();
        }
    }
    
    private static void writeField(OutputStream out, String name, String value) throws IOException {
        StringBuilder sb = new StringBuilder();
        sb.append("--").append(BOUNDARY).append(CRLF);
        sb.append("Content-Disposition: form-data; name=\"").append(name).append("\"").append(CRLF);
        sb.append(CRLF);
        sb.append(value).append(CRLF);
        out.write(sb.toString().getBytes(StandardCharsets.UTF_8));
    }
    
    private static void writeFile(OutputStream out, String fieldName, Path filePath) throws IOException {
        String fileName = filePath.getFileName().toString();
        
        StringBuilder sb = new StringBuilder();
        sb.append("--").append(BOUNDARY).append(CRLF);
        sb.append("Content-Disposition: form-data; name=\"")
          .append(fieldName).append("\"; filename=\"")
          .append(fileName).append("\"").append(CRLF);
        sb.append("Content-Type: ").append(probeContentType(filePath)).append(CRLF);
        sb.append(CRLF);
        out.write(sb.toString().getBytes(StandardCharsets.UTF_8));
        
        // Write file bytes
        Files.copy(filePath, out);
        
        out.write(CRLF.getBytes(StandardCharsets.UTF_8));
    }
    
    /**
     * Upload a single file
     */
    public static ApiResponse uploadFile(String url, String fieldName, Path filePath) throws IOException {
        Map<String, Path> files = new HashMap<>();
        files.put(fieldName, filePath);
        return uploadFiles(url, files, null);
    }
    
    /**
     * Probe content type or return default
     */
    private static String probeContentType(Path path) {
        try {
            String type = Files.probeContentType(path);
            return type != null ? type : "application/octet-stream";
        } catch (IOException e) {
            return "application/octet-stream";
        }
    }
    
    /**
     * Read input stream to string
     */
    private static String readInputStream(InputStream is) throws IOException {
        if (is == null) return "";
        
        try (BufferedReader reader = new BufferedReader(
                new InputStreamReader(is, StandardCharsets.UTF_8))) {
            StringBuilder sb = new StringBuilder();
            String line;
            while ((line = reader.readLine()) != null) {
                sb.append(line).append("\n");
            }
            return sb.toString().trim();
        }
    }
    

    // Example usage
    public static void main(String[] args) {
        try {
            // Example 1: Upload single file
//            Path file1 = Paths.get("build.properties");
//            ApiResponse response1 = uploadFile(
//                "http://localhost:3005/compile_asn",
//                "file",
//                file1
//            );
//            
//            log("Status: " + response1.getStatusCode());
//            log("JSON Response: " + response1.getJsonBody());
//            log("Content-Type: " + response1.getHeader("Content-Type"));

            // Example 2: Upload multiple files with additional fields
            Map<String, Path> files = new HashMap<>();
            files.put("file1", Paths.get("build.properties"));
            files.put("file2", Paths.get("pom.xml"));
            
            
            Map<String, String> fields = new HashMap<>();
            fields.put("backend", "titan");
            fields.put("command", "compiler");
            fields.put("target", "ttcn-3");
            
            ApiResponse response2 = uploadFiles(
                "http://localhost:3005/compile_asn",
                files,
                fields
            );
            
            log("\nMultiple files uploaded:");
            log("Status: " + response2.getStatusCode());
            log("Response: " + response2.getJsonBody());
            
        } catch (IOException e) {
            log("ERROR: Upload failed: " + e.getMessage());
            e.printStackTrace();
        }
    }
    
    public static void log(String message) {
    	if (T3Q.getLogLevel() == LogLevel.DEBUG) {
    		System.out.println(message);
    	}
    }
}
 No newline at end of file
+520 −0

File added.

Preview size limit exceeded, changes collapsed.

Loading