diff options
author | Pooja03 <pm00501616@techmahindra.com> | 2018-09-25 11:16:04 +0530 |
---|---|---|
committer | Pooja03 <pm00501616@techmahindra.com> | 2018-09-25 11:16:04 +0530 |
commit | 7f9114df5c5ea043906f05df6fd5734955d8685a (patch) | |
tree | f705343ef1dd001809f3482a23394a29df38cf77 | |
parent | d6680d72e53df89e607f3aa2f84e4b1a28c74a88 (diff) |
Config from docker env params
Taking Config from docker env parameters if CONSUL_HOST flag is present
Change-Id: Ice897f9414186409bdbc3db79eee7b5a971f1cdc
Issue-ID: DCAEGEN2-338
Signed-off-by: Pooja03 <pm00501616@techmahindra.com>
-rw-r--r-- | pom.xml | 8 | ||||
-rw-r--r-- | snmpmapper/pom.xml | 243 | ||||
-rw-r--r-- | snmpmapper/run.sh | 6 | ||||
-rw-r--r-- | snmpmapper/settings.xml | 87 | ||||
-rw-r--r-- | snmpmapper/src/assembly/dep.xml | 57 | ||||
-rw-r--r-- | snmpmapper/src/main/java/org/onap/dcaegen2/services/mapper/snmpmapper/DAO/MappingFileDAOImpl.java | 46 | ||||
-rw-r--r-- | snmpmapper/src/main/resources/application.properties | 2 | ||||
-rw-r--r-- | snmpmapper/src/main/resources/logback.xml | 79 | ||||
-rw-r--r-- | snmpmapper/src/main/scripts/run.sh | 2 |
9 files changed, 520 insertions, 10 deletions
@@ -70,7 +70,7 @@ <httpclient.version>4.5.6</httpclient.version> <commons.lang3.version>3.5</commons.lang3.version> - <docker.maven.version>1.0.0</docker.maven.version> + <docker.maven.version>1.1.1</docker.maven.version> <!--TESTING DEPENDENCIES --> <junit.version>4.12</junit.version> @@ -129,12 +129,12 @@ <dependencies> <!-- LOGGING --> - <dependency> + <!-- <dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-api</artifactId> <version>${slf4j.version}</version> <scope>provided</scope> - </dependency> + </dependency> --> <!-- UTILITIES --> @@ -562,7 +562,7 @@ <artifactId>docker-maven-plugin</artifactId> <version>${docker.maven.version}</version> <configuration> - <skipDockerBuild>true</skipDockerBuild> + <skipDockerBuild>false</skipDockerBuild> </configuration> </plugin> </plugins> diff --git a/snmpmapper/pom.xml b/snmpmapper/pom.xml index f0ca669..b049c5f 100644 --- a/snmpmapper/pom.xml +++ b/snmpmapper/pom.xml @@ -1,4 +1,15 @@ <?xml version="1.0" encoding="UTF-8"?> +<!-- * ============LICENSE_START======================================================= + * ONAP : DCAEGEN2/services/mapper * ================================================================================ + * Copyright 2018 TechMahindra *================================================================================= + * 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. + * ============LICENSE_END========================================================= --> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> @@ -20,9 +31,26 @@ <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding> - <java.version>1.8</java.version> - </properties> + <java.version>8</java.version> + + <docker.image.name>onap/org.onap.dcaegen2.services.mapper.snmpmapper</docker.image.name> + + <!-- TEST SETTINGS --> + <surefire.redirectTestOutputToFile>true</surefire.redirectTestOutputToFile> + + <!-- PLUGIN SETTINGS --> + <dependency.locations.enabled>false</dependency.locations.enabled> + + <!-- NEXUS RELATED SETTINGS --> + <nexusproxy>https://nexus.onap.org</nexusproxy> + <snapshots.path>content/repositories/snapshots/</snapshots.path> + <releases.path>content/repositories/releases/</releases.path> + <site.path> + content/sites/site/org/onap/dcaegen2/collectors/ves/${project.artifactId}/${project.version} + </site.path> + <maven.build.timestamp.format>yyyyMMdd'T'HHmmss</maven.build.timestamp.format> + </properties> <dependencies> <dependency> <groupId>org.springframework.webflow</groupId> @@ -93,16 +121,225 @@ </dependencies> <build> + + <pluginManagement> + <plugins> + <plugin> + <artifactId>maven-assembly-plugin</artifactId> + <version>3.1.0</version> + </plugin> + <plugin> + <groupId>com.spotify</groupId> + <artifactId>docker-maven-plugin</artifactId> + <version>1.1.1</version> + </plugin> + </plugins> + </pluginManagement> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> <version>2.0.0.RELEASE</version> </plugin> + <plugin> + <groupId>org.springframework.boot</groupId> + <artifactId>spring-boot-maven-plugin</artifactId> + <version>2.0.0.RELEASE</version> + <executions> + <execution> + <goals> + <goal>repackage</goal> + </goals> + <configuration> + <mainClass>org.onap.dcaegen2.services.mapper.snmpmapper.SnmpmapperApplication</mainClass> + </configuration> + </execution> + </executions> + </plugin> + <plugin> + <artifactId>maven-jar-plugin</artifactId> + <configuration> + <archive> + <manifest> + <addDefaultImplementationEntries>true</addDefaultImplementationEntries> + </manifest> + <manifestEntries> + <Implementation-Build-Version>${project.version}</Implementation-Build-Version> + </manifestEntries> + </archive> + </configuration> + </plugin> + <plugin> + + <artifactId>maven-assembly-plugin</artifactId> + <configuration> + <descriptors> + <descriptor>src/assembly/dep.xml</descriptor> + </descriptors> + <attach>false</attach> + <appendAssemblyId>false</appendAssemblyId> + <updateOnly>true</updateOnly> + </configuration> + <executions> + <execution> + <id>make-assembly</id> + <phase>package</phase> + <goals> + <goal>single</goal> + </goals> + </execution> + </executions> + </plugin> + + <!-- Spotify plugin to build and push docker image --> + + <plugin> + <groupId>com.spotify</groupId> + <artifactId>docker-maven-plugin</artifactId> + <version>1.1.1</version> + <configuration> + <serverId>${onap.nexus.dockerregistry.daily}</serverId> + <imageName>${docker.image.name}</imageName> + <imageTags> + <tag>latest</tag> + </imageTags> + <baseImage>ubuntu:16.04</baseImage> + <env> + <HOSTALIASES>/etc/host.aliases</HOSTALIASES> + <HOME>/opt/app/SnmpMapper</HOME> + </env> + <workdir>/opt/app/SnmpMapper</workdir> + <resources> + <resource> + <targetPath>.</targetPath> + + <directory>${project.build.directory}/${project.artifactId}-${project.version}</directory> + </resource> + </resources> + <runs> + <run>chmod +x bin/run.sh</run> + <run> + <![CDATA[apt-get update && apt-get install -y curl && apt-get install -y openjdk-8-jdk && apt-get install -y vim && apt-get clean all]]> + </run> + </runs> + <exposes> + <expose>8080</expose> + </exposes> + <entryPoint>bin/run.sh</entryPoint> + + </configuration> + <executions> + <execution> + <id>build-image</id> + <phase>package</phase> + <goals> + <goal>build</goal> + </goals> + </execution> + <execution> + <id>tag-and-push-image-latest</id> + <phase>deploy</phase> + <goals> + <goal>tag</goal> + </goals> + <configuration> + <image>${docker.image.name}:latest</image> + <newName>${onap.nexus.dockerregistry.daily}/${docker.image.name}:latest</newName> + <pushImage>true</pushImage> + </configuration> + </execution> + <execution> + <id>tag-and-push-image-with-version</id> + <phase>deploy</phase> + <goals> + <goal>tag</goal> + </goals> + <configuration> + <image>${docker.image.name}:latest</image> + <newName>${onap.nexus.dockerregistry.daily}/${docker.image.name}:${project.version} + </newName> + <pushImage>true</pushImage> + </configuration> + </execution> + <execution> + <id>tag-and-push-image-with-version-and-date</id> + <phase>deploy</phase> + <goals> + <goal>tag</goal> + </goals> + <configuration> + <image>${docker.image.name}:latest</image> + <newName> + ${onap.nexus.dockerregistry.daily}/${docker.image.name}:${project.version}-${maven.build.timestamp}Z + </newName> + <pushImage>true</pushImage> + </configuration> + </execution> + </executions> + </plugin> + <plugin> + <groupId>org.codehaus.mojo</groupId> + <artifactId>build-helper-maven-plugin</artifactId> + <version>1.9.1</version> + <executions> + <execution> + <id>add-source</id> + <phase>generate-sources</phase> + <goals> + <goal>add-source</goal> + </goals> + <configuration> + <sources> + <source>src/gen/java</source> + </sources> + </configuration> + </execution> + <!-- <execution> <id>regex-property</id> <goals> <goal>regex-property</goal> + </goals> <configuration> <name>docker.version</name> <value>${project.version}</value> + <regex>(^[0-9]+.[0-9]+.[0-9]+$)</regex> <replacement>$1-STAGING</replacement> + <failIfNoMatch>false</failIfNoMatch> </configuration> </execution> --> + </executions> + </plugin> </plugins> - <finalName>snmpmapper</finalName> + <!-- <finalName>snmpmapper</finalName> --> </build> + + + <profiles> + <profile> + <id>with-system-proxy</id> + <build> + <plugins> + <plugin> + <groupId>com.spotify</groupId> + <artifactId>docker-maven-plugin</artifactId> + <configuration> + <buildArgs> + <http_proxy>${env.http_proxy}</http_proxy> + </buildArgs> + </configuration> + </plugin> + + </plugins> + + </build> + </profile> + </profiles> + + + <repositories> + <repository> + <id>spring-releases</id> + <url>https://repo.spring.io/libs-release</url> + </repository> + </repositories> + <pluginRepositories> + <pluginRepository> + <id>spring-releases</id> + <url>https://repo.spring.io/libs-release</url> + </pluginRepository> + </pluginRepositories> </project> diff --git a/snmpmapper/run.sh b/snmpmapper/run.sh new file mode 100644 index 0000000..d64d485 --- /dev/null +++ b/snmpmapper/run.sh @@ -0,0 +1,6 @@ +#!/bin/sh +java -jar /opt/snmpmapper.jar & +echo "Sleeping for 30 seconds to get application ready" +sleep 30s +echo"invoking curl" +curl -X GET http://localhost:8080 diff --git a/snmpmapper/settings.xml b/snmpmapper/settings.xml new file mode 100644 index 0000000..03047a3 --- /dev/null +++ b/snmpmapper/settings.xml @@ -0,0 +1,87 @@ +<!-- +================================================================================ +Copyright (c) 2017-2018 AT&T Intellectual Property. All rights reserved. +================================================================================ +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. +============LICENSE_END========================================================= + +ECOMP is a trademark and service mark of AT&T Intellectual Property. +--> +<?xml version="1.0" encoding="UTF-8"?> + +<settings xmlns="http://maven.apache.org/SETTINGS/1.0.0" + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://maven.apache.org/SETTINGS/1.0.0 http://maven.apache.org/xsd/settings-1.0.0.xsd"> + + <profiles> + <profile> + <id>open-ecomp</id> + <activation> + <activeByDefault>true</activeByDefault> + </activation> + <repositories> + <repository> + <id>osecomp-nexus-releases</id> + <name>OSECOMP Release Repository</name> + <url>https://ecomp-nexus:8443/repository/maven-releases</url> + </repository> + <repository> + <id>osecomp-nexus-snapshots</id> + <name>OSECOMP Snapshot Repository</name> + <url>https://ecomp-nexus:8443/repository/maven-snapshots</url> + </repository> + <repository> + <id>eclipse</id> + <url>https://repo.eclipse.org/content/repositories/releases</url> + <releases> + <enabled>true</enabled> + <updatePolicy>daily</updatePolicy> + </releases> + <snapshots> + <enabled>false</enabled> + </snapshots> + </repository> + </repositories> + </profile> + + </profiles> + + <activeProfiles> + <activeProfile>open-ecomp</activeProfile> + </activeProfiles> + + <servers> + <server> + <id>osecomp-nexus</id> + <username>${openecomp.nexus.user}</username> + <password>${openecomp.nexus.password}</password> + </server> + <server> + <id>osecomp-nexus-releases</id> + <username>${openecomp.nexus.user}</username> + <password>${openecomp.nexus.password}</password> + </server> + <server> + <id>osecomp-nexus-snapshots</id> + <username>${openecomp.nexus.user}</username> + <password>${openecomp.nexus.password}</password> + </server> + <server> + <username>${openecomp.nexus.user}</username> + <password>${openecomp.nexus.password}</password> + <id>dcae-javadoc</id> + </server> + + </servers> + +</settings> diff --git a/snmpmapper/src/assembly/dep.xml b/snmpmapper/src/assembly/dep.xml new file mode 100644 index 0000000..2859272 --- /dev/null +++ b/snmpmapper/src/assembly/dep.xml @@ -0,0 +1,57 @@ +<!-- +================================================================================ +Copyright (c) 2017-2018 AT&T Intellectual Property. All rights reserved. +Copyright (c) 2018 Nokia. All rights reserved. +================================================================================ +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. +============LICENSE_END========================================================= +--> + +<assembly xmlns="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/2.0.0" + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/2.0.0 http://maven.apache.org/xsd/assembly-2.0.0.xsd"> + + <id>bundle</id> + <includeBaseDirectory>false</includeBaseDirectory> + <formats> + <format>dir</format> + </formats> + + <fileSets> + <fileSet> + <directory>src/main/scripts</directory> + <outputDirectory>bin</outputDirectory> + <includes> + <include>**/*.sh</include> + </includes> + <fileMode>0755</fileMode> + <lineEnding>unix</lineEnding> + </fileSet> + + <fileSet> + <directory>src/main/resources</directory> + <outputDirectory>conf</outputDirectory> + <includes> + <include>**/defaultSnmpMappingFile.xml</include> + </includes> + </fileSet> + </fileSets> + <dependencySets> + <dependencySet> + <scope>runtime</scope> + <useProjectArtifact>true</useProjectArtifact> + <unpack>false</unpack> + <outputDirectory>lib</outputDirectory> + </dependencySet> + </dependencySets> +</assembly> diff --git a/snmpmapper/src/main/java/org/onap/dcaegen2/services/mapper/snmpmapper/DAO/MappingFileDAOImpl.java b/snmpmapper/src/main/java/org/onap/dcaegen2/services/mapper/snmpmapper/DAO/MappingFileDAOImpl.java index 93fd1a5..3d18d1d 100644 --- a/snmpmapper/src/main/java/org/onap/dcaegen2/services/mapper/snmpmapper/DAO/MappingFileDAOImpl.java +++ b/snmpmapper/src/main/java/org/onap/dcaegen2/services/mapper/snmpmapper/DAO/MappingFileDAOImpl.java @@ -24,11 +24,13 @@ import java.sql.Connection; import java.sql.DriverManager; import java.sql.PreparedStatement; import java.sql.SQLException; - -import org.onap.dcaegen2.services.mapper.snmpmapper.exception.SnmpMapperException; +import java.util.Map; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; +import org.springframework.boot.SpringApplication; +import org.springframework.context.ApplicationContext; import org.springframework.stereotype.Repository; import org.springframework.web.multipart.MultipartFile; @@ -46,9 +48,46 @@ public class MappingFileDAOImpl implements MappingFileDAO { String user; @Value("${spring.datasource.password}") String pwd; + @Autowired private ApplicationContext applicationContext; + private static Map<String, String> env; @Override public String uploadMappingFile(MultipartFile mappingFile, String enterpriseid) throws SQLException, IOException { + + env = System.getenv(); + for (Map.Entry<String, String> entry : env.entrySet()) { + LOGGER.info(entry.getKey() + ":" + entry.getValue()); + } + + if (env.containsKey("CONSUL_HOST") && env.containsKey("CONFIG_BINDING_SERVICE") && env.containsKey("HOSTNAME")) { + //TODO - Add logic to talk to Consul and CBS to get the configuration. For now, we will refer to configuration coming from docker env parameters + + LOGGER.info(">>>Dynamic configuration to be used"); + + if( (env.get("MR_DMAAPHOST")==null || + (env.get("MR_DMAAPHOST")==null || + (env.get("MR_DEFAULT_PORT_NUMBER")==null || + (env.get("URL_JDBC")==null || + (env.get("JDBC_USERNAME")==null || + (env.get("JDBC_PASSWORD")==null ))))))) { + + + LOGGER.error("Some docker environment parameter is missing. Sample Usage is -\n sudo docker run -d -p 8085:8085/tcp --env URL_JDBC=jdbc:postgresql://10.53.172.129:5432/dummy --env JDBC_USERNAME=ngpuser --env JDBC_PASSWORD=root --env MR_DMAAPHOST=10.10.10.10 --env MR_DEFAULT_PORT_NUMBER=3904 --env CONSUL_HOST=10.53.172.109 --env HOSTNAME=mvp-dcaegen2-collectors-ves --env CONFIG_BINDING_SERVICE=config_binding_service -e DMAAPHOST='10.53.172.156' onap/org.onap.dcaegen2.services.mapper.vesadapter.universalvesadaptor:latest"); + System.exit(SpringApplication.exit(applicationContext, () -> {LOGGER.error("Application is stoped please provide the above environment parameter during docker run");return-1;})); + + }else { + + url=env.get("URL_JDBC"); + user=env.get("JDBC_USERNAME"); + pwd=env.get("JDBC_PASSWORD"); + } + + } else { + LOGGER.info(">>>Static configuration to be used"); + } + + + try (Connection con = DriverManager.getConnection(url, user, pwd)) { LOGGER.debug("Connection established successfully"); PreparedStatement pstmt = con.prepareStatement( @@ -61,6 +100,9 @@ public class MappingFileDAOImpl implements MappingFileDAO { pstmt.executeUpdate(); + }catch (Exception e) { + LOGGER.error("Error occured due to :" + e.getMessage()); + e.printStackTrace(); } return "Uploaded successfully"; diff --git a/snmpmapper/src/main/resources/application.properties b/snmpmapper/src/main/resources/application.properties index 2121542..c9d1255 100644 --- a/snmpmapper/src/main/resources/application.properties +++ b/snmpmapper/src/main/resources/application.properties @@ -1,4 +1,4 @@ -server.port=9090 +server.port=8080 #spring.datasource.url=jdbc:postgresql://10.49.16.19:5432/dummy #spring.datasource.username=postgres #spring.datasource.password=root diff --git a/snmpmapper/src/main/resources/logback.xml b/snmpmapper/src/main/resources/logback.xml new file mode 100644 index 0000000..e979ca2 --- /dev/null +++ b/snmpmapper/src/main/resources/logback.xml @@ -0,0 +1,79 @@ +<?xml version="1.0" encoding="UTF-8"?> +<configuration> + + <property name="DEV_HOME" value="logs" /> + + <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender"> + <layout class="ch.qos.logback.classic.PatternLayout"> + <Pattern> + %d{yyyy-MM-dd HH:mm:ss} [%thread] %-5level %logger{36} - %msg%n + </Pattern> + </layout> + </appender> + + <appender name="FILE-AUDIT" + class="ch.qos.logback.core.rolling.RollingFileAppender"> + <file>${DEV_HOME}/debug.log</file> + <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder"> + <Pattern> + %d{yyyy-MM-dd HH:mm:ss} [%thread] %-5level %logger{36} - %msg%n + </Pattern> + </encoder> + + <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy"> + <!-- rollover daily --> + <fileNamePattern>${DEV_HOME}/archived/debug.%d{yyyy-MM-dd}.%i.log + </fileNamePattern> + <timeBasedFileNamingAndTriggeringPolicy + class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP"> + <maxFileSize>10MB</maxFileSize> + </timeBasedFileNamingAndTriggeringPolicy> + </rollingPolicy> + + </appender> + + <appender name="FILE-ERROR" + class="ch.qos.logback.core.rolling.RollingFileAppender"> + <filter class="ch.qos.logback.classic.filter.LevelFilter"> + <level>ERROR</level> + <onMatch>ACCEPT</onMatch> + <onMismatch>DENY</onMismatch> + </filter> + <file>${DEV_HOME}/error.log</file> + <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder"> + <Pattern> + %d{yyyy-MM-dd HH:mm:ss} %logger{36} - %msg%n + </Pattern> + </encoder> + + <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy"> + <!-- rollover daily --> + <fileNamePattern>${DEV_HOME}/archived/error.%d{yyyy-MM-dd}.%i.log + </fileNamePattern> + <timeBasedFileNamingAndTriggeringPolicy + class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP"> + <maxFileSize>10MB</maxFileSize> + </timeBasedFileNamingAndTriggeringPolicy> + </rollingPolicy> + + </appender> + + <!-- Send logs to both console and file audit --> + <logger name="org.onap.dcaegen2.services.mapper.snmpmapper" level="debug" additivity="false"> + <appender-ref ref="FILE-AUDIT" /> + <appender-ref ref="STDOUT" /> + </logger> + <logger name="org.onap.dcaegen2.services.mapper.snmpmapper" level="debug" additivity="false"> + <appender-ref ref="FILE-AUDIT" /> + <appender-ref ref="FILE-ERROR" /> + <appender-ref ref="STDOUT" /> + </logger> - + <!-- <logger name="org.onap.universalvesadapter.adapter" level="error" additivity="false"> + <appender-ref ref="FILE-ERROR" /> + </logger> --> + + + + + +</configuration>
\ No newline at end of file diff --git a/snmpmapper/src/main/scripts/run.sh b/snmpmapper/src/main/scripts/run.sh new file mode 100644 index 0000000..e85fe59 --- /dev/null +++ b/snmpmapper/src/main/scripts/run.sh @@ -0,0 +1,2 @@ +#!/bin/sh +java -cp "./conf:./lib/*" org.onap.dcaegen2.services.mapper.snmpmapper.SnmpmapperApplication
\ No newline at end of file |