forked from finos/legend-pure
-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
48f97ae
commit 0696d75
Showing
6 changed files
with
682 additions
and
0 deletions.
There are no files selected for viewing
160 changes: 160 additions & 0 deletions
160
.../src/main/java/org/finos/legend/pure/m3/serialization/compiler/file/FilePathProvider.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,160 @@ | ||
// Copyright 2024 Goldman Sachs | ||
// | ||
// Licensed under the Apache License, Version 2.0 (the "License"); | ||
// you may not use this file except in compliance with the License. | ||
// You may obtain a copy of the License at | ||
// | ||
// http://www.apache.org/licenses/LICENSE-2.0 | ||
// | ||
// Unless required by applicable law or agreed to in writing, software | ||
// distributed under the License is distributed on an "AS IS" BASIS, | ||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
// See the License for the specific language governing permissions and | ||
// limitations under the License. | ||
|
||
package org.finos.legend.pure.m3.serialization.compiler.file; | ||
|
||
import org.finos.legend.pure.m3.serialization.compiler.ExtensibleSerializer; | ||
|
||
import java.nio.file.FileSystems; | ||
import java.util.Arrays; | ||
|
||
public class FilePathProvider extends ExtensibleSerializer<FilePathProviderExtension> | ||
{ | ||
private FilePathProvider(Iterable<? extends FilePathProviderExtension> extensions, int defaultVersion) | ||
{ | ||
super(extensions, defaultVersion); | ||
} | ||
|
||
public String getElementFilePath(String elementPath) | ||
{ | ||
return getElementFilePath(elementPath, null); | ||
} | ||
|
||
public String getElementFilePath(String elementPath, String fsSeparator) | ||
{ | ||
return getElementFilePath(elementPath, fsSeparator, getDefaultExtension()); | ||
} | ||
|
||
public String getElementFilePath(String elementPath, int version) | ||
{ | ||
return getElementFilePath(elementPath, null, version); | ||
} | ||
|
||
public String getElementFilePath(String elementPath, String fsSeparator, int version) | ||
{ | ||
return getElementFilePath(elementPath, fsSeparator, getExtension(version)); | ||
} | ||
|
||
private String getElementFilePath(String elementPath, String fsSeparator, FilePathProviderExtension extension) | ||
{ | ||
return extension.getElementFilePath( | ||
validateNonEmpty(elementPath, "element path"), | ||
resolveFSSeparator(fsSeparator)); | ||
} | ||
|
||
public String getModuleMetadataFilePath(String moduleName) | ||
{ | ||
return getModuleMetadataFilePath(moduleName, null); | ||
} | ||
|
||
public String getModuleMetadataFilePath(String moduleName, String fsSeparator) | ||
{ | ||
return getModuleMetadataFilePath(moduleName, fsSeparator, getDefaultExtension()); | ||
} | ||
|
||
public String getModuleMetadataFilePath(String moduleName, int version) | ||
{ | ||
return getModuleMetadataFilePath(moduleName, null, version); | ||
} | ||
|
||
public String getModuleMetadataFilePath(String moduleName, String fsSeparator, int version) | ||
{ | ||
return getModuleMetadataFilePath(moduleName, fsSeparator, getExtension(version)); | ||
} | ||
|
||
private String getModuleMetadataFilePath(String moduleName, String fsSeparator, FilePathProviderExtension extension) | ||
{ | ||
return extension.getModuleMetadataFilePath( | ||
validateNonEmpty(moduleName, "module name"), | ||
resolveFSSeparator(fsSeparator)); | ||
} | ||
|
||
private static String validateNonEmpty(String string, String description) | ||
{ | ||
if ((string == null) || string.isEmpty()) | ||
{ | ||
throw new IllegalArgumentException(description + " may not be null or empty"); | ||
} | ||
return string; | ||
} | ||
|
||
private static String resolveFSSeparator(String fsSeparator) | ||
{ | ||
return (fsSeparator == null) ? getDefaultFSSeparator() : fsSeparator; | ||
} | ||
|
||
private static String getDefaultFSSeparator() | ||
{ | ||
return FileSystems.getDefault().getSeparator(); | ||
} | ||
|
||
public static Builder builder() | ||
{ | ||
return new Builder(); | ||
} | ||
|
||
public static class Builder extends ExtensibleSerializer.AbstractBuilder<FilePathProviderExtension, FilePathProvider> | ||
{ | ||
private Builder() | ||
{ | ||
} | ||
|
||
public Builder withExtension(FilePathProviderExtension extension) | ||
{ | ||
addExtension(extension); | ||
return this; | ||
} | ||
|
||
public Builder withExtensions(Iterable<? extends FilePathProviderExtension> extensions) | ||
{ | ||
addExtensions(extensions); | ||
return this; | ||
} | ||
|
||
public Builder withExtensions(FilePathProviderExtension... extensions) | ||
{ | ||
return withExtensions(Arrays.asList(extensions)); | ||
} | ||
|
||
public Builder withLoadedExtensions(ClassLoader classLoader) | ||
{ | ||
loadExtensions(classLoader); | ||
return this; | ||
} | ||
|
||
public Builder withLoadedExtensions() | ||
{ | ||
loadExtensions(); | ||
return this; | ||
} | ||
|
||
public Builder withDefaultVersion(int defaultVersion) | ||
{ | ||
setDefaultVersion(defaultVersion); | ||
return this; | ||
} | ||
|
||
@Override | ||
protected FilePathProvider build(Iterable<FilePathProviderExtension> extensions, int defaultVersion) | ||
{ | ||
return new FilePathProvider(extensions, defaultVersion); | ||
} | ||
|
||
@Override | ||
protected Class<FilePathProviderExtension> getExtensionClass() | ||
{ | ||
return FilePathProviderExtension.class; | ||
} | ||
} | ||
} |
42 changes: 42 additions & 0 deletions
42
.../java/org/finos/legend/pure/m3/serialization/compiler/file/FilePathProviderExtension.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,42 @@ | ||
// Copyright 2024 Goldman Sachs | ||
// | ||
// Licensed under the Apache License, Version 2.0 (the "License"); | ||
// you may not use this file except in compliance with the License. | ||
// You may obtain a copy of the License at | ||
// | ||
// http://www.apache.org/licenses/LICENSE-2.0 | ||
// | ||
// Unless required by applicable law or agreed to in writing, software | ||
// distributed under the License is distributed on an "AS IS" BASIS, | ||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
// See the License for the specific language governing permissions and | ||
// limitations under the License. | ||
|
||
package org.finos.legend.pure.m3.serialization.compiler.file; | ||
|
||
import org.finos.legend.pure.m3.serialization.compiler.SerializerExtension; | ||
|
||
public interface FilePathProviderExtension extends SerializerExtension | ||
{ | ||
/** | ||
* Get the relative file path for the binary file for the given element. This should be a relative file path, and | ||
* must not start with the path separator. It should never be null or empty. Each name in the path should be no | ||
* longer than 255 bytes when encoded in UTF-16. | ||
* | ||
* @param elementPath concrete element path | ||
* @param fsSeparator filesystem path separator | ||
* @return relative file path | ||
*/ | ||
String getElementFilePath(String elementPath, String fsSeparator); | ||
|
||
/** | ||
* Get the relative file path for the metadata file for the given module. This should be a relative file path, and | ||
* must not start with the path separator. Tt should never be null or empty. Each name in the path should be no | ||
* longer than 255 bytes when encoded in UTF-16. | ||
* | ||
* @param moduleName module name | ||
* @param fsSeparator filesystem path separator | ||
* @return relative file path | ||
*/ | ||
String getModuleMetadataFilePath(String moduleName, String fsSeparator); | ||
} |
108 changes: 108 additions & 0 deletions
108
.../org/finos/legend/pure/m3/serialization/compiler/file/v1/FilePathProviderExtensionV1.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,108 @@ | ||
// Copyright 2024 Goldman Sachs | ||
// | ||
// Licensed under the Apache License, Version 2.0 (the "License"); | ||
// you may not use this file except in compliance with the License. | ||
// You may obtain a copy of the License at | ||
// | ||
// http://www.apache.org/licenses/LICENSE-2.0 | ||
// | ||
// Unless required by applicable law or agreed to in writing, software | ||
// distributed under the License is distributed on an "AS IS" BASIS, | ||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
// See the License for the specific language governing permissions and | ||
// limitations under the License. | ||
|
||
package org.finos.legend.pure.m3.serialization.compiler.file.v1; | ||
|
||
import org.eclipse.collections.api.factory.Lists; | ||
import org.eclipse.collections.api.list.ImmutableList; | ||
import org.finos.legend.pure.m3.navigation.M3Paths; | ||
import org.finos.legend.pure.m3.navigation.PackageableElement.PackageableElement; | ||
import org.finos.legend.pure.m3.serialization.compiler.file.FilePathProviderExtension; | ||
|
||
public class FilePathProviderExtensionV1 implements FilePathProviderExtension | ||
{ | ||
// UTF-16 uses 2 bytes per Java char, possibly plus a byte order marker of 2 bytes | ||
// Since the name must be <= 255 bytes in UTF-16, 126 is the length limit for names (126 * 2 + 2 = 254) | ||
private static final int NAME_LEN_LIMIT = 126; | ||
private static final int SUFFIX_LEN = 16; | ||
|
||
private static final String ELEMENT_FILE_EXTENSION = ".pelt"; | ||
|
||
private static final ImmutableList<String> MODULE_FILE_DIR = Lists.immutable.with("legend", "pure", "module"); | ||
private static final String MODULE_FILE_EXTENSION = ".pmf"; | ||
|
||
@Override | ||
public int version() | ||
{ | ||
return 1; | ||
} | ||
|
||
@Override | ||
public String getElementFilePath(String elementPath, String fsSeparator) | ||
{ | ||
if (PackageableElement.DEFAULT_PATH_SEPARATOR.equals(elementPath)) | ||
{ | ||
return M3Paths.Root + ELEMENT_FILE_EXTENSION; | ||
} | ||
|
||
StringBuilder builder = new StringBuilder(elementPath.length() + ELEMENT_FILE_EXTENSION.length()); | ||
int start = 0; | ||
int sepLen = PackageableElement.DEFAULT_PATH_SEPARATOR.length(); | ||
int end; | ||
while ((end = elementPath.indexOf(PackageableElement.DEFAULT_PATH_SEPARATOR, start)) != -1) | ||
{ | ||
appendName(builder, elementPath, start, end, null).append(fsSeparator); | ||
start = end + sepLen; | ||
} | ||
|
||
return appendName(builder, elementPath, start, elementPath.length(), ELEMENT_FILE_EXTENSION).toString(); | ||
} | ||
|
||
@Override | ||
public String getModuleMetadataFilePath(String moduleName, String fsSeparator) | ||
{ | ||
StringBuilder builder = new StringBuilder(moduleName.length() + MODULE_FILE_EXTENSION.length() + (MODULE_FILE_DIR.size() * fsSeparator.length()) + 16); | ||
MODULE_FILE_DIR.forEach(name -> builder.append(name).append(fsSeparator)); | ||
return appendName(builder, moduleName, 0, moduleName.length(), MODULE_FILE_EXTENSION).toString(); | ||
} | ||
|
||
private static StringBuilder appendName(StringBuilder builder, String string, int start, int end, String extension) | ||
{ | ||
int extLen = (extension == null) ? 0 : extension.length(); | ||
int len = (end - start) + extLen; | ||
if (len < NAME_LEN_LIMIT) | ||
{ | ||
// append the name, possibly plus extension, as it's below the limit | ||
builder.append(string, start, end); | ||
return (extension == null) ? builder : builder.append(extension); | ||
} | ||
|
||
// if the name is too long, append an initial segment plus a fixed length suffix computed from the overage | ||
int overageStart = start + NAME_LEN_LIMIT - SUFFIX_LEN - extLen; | ||
if (Character.isLowSurrogate(string.charAt(overageStart)) && Character.isHighSurrogate(string.charAt(overageStart - 1))) | ||
{ | ||
// avoid splitting the string in the middle of a supplementary pair | ||
overageStart--; | ||
} | ||
builder.ensureCapacity(builder.length() + (overageStart - start) + SUFFIX_LEN + extLen); | ||
builder.append(string, start, overageStart); | ||
String suffix = getOverageSuffix(string, overageStart, end); | ||
for (int i = suffix.length(); i < SUFFIX_LEN; i++) | ||
{ | ||
builder.append('0'); | ||
} | ||
builder.append(suffix); | ||
return (extension == null) ? builder : builder.append(extension); | ||
} | ||
|
||
private static String getOverageSuffix(String string, int start, int end) | ||
{ | ||
long value = 0; | ||
for (int i = start, cp; i < end; i += Character.charCount(cp)) | ||
{ | ||
value = (31 * value) + (cp = string.codePointAt(i)); | ||
} | ||
return Long.toHexString(value); | ||
} | ||
} |
1 change: 1 addition & 0 deletions
1
...F/services/org.finos.legend.pure.m3.serialization.compiler.file.FilePathProviderExtension
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
org.finos.legend.pure.m3.serialization.compiler.file.v1.FilePathProviderExtensionV1 |
Oops, something went wrong.