otel working

main
Brett 2023-11-16 20:29:46 -05:00
parent b2b3bc7f93
commit bc1aa49115
34 changed files with 296 additions and 62 deletions

13
.idea/compiler.xml Normal file
View File

@ -0,0 +1,13 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="CompilerConfiguration">
<annotationProcessing>
<profile name="Maven default annotation processors profile" enabled="true">
<sourceOutputDir name="target/generated-sources/annotations" />
<sourceTestOutputDir name="target/generated-test-sources/test-annotations" />
<outputRelativeToContentRoot value="true" />
<module name="Assignment 2 Java" />
</profile>
</annotationProcessing>
</component>
</project>

7
.idea/encodings.xml Normal file
View File

@ -0,0 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="Encoding">
<file url="file://$PROJECT_DIR$/src/main/java" charset="UTF-8" />
<file url="file://$PROJECT_DIR$/src/main/resources" charset="UTF-8" />
</component>
</project>

20
.idea/jarRepositories.xml Normal file
View File

@ -0,0 +1,20 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="RemoteRepositoriesConfiguration">
<remote-repository>
<option name="id" value="central" />
<option name="name" value="Central Repository" />
<option name="url" value="https://repo.maven.apache.org/maven2" />
</remote-repository>
<remote-repository>
<option name="id" value="central" />
<option name="name" value="Maven Central repository" />
<option name="url" value="https://repo1.maven.org/maven2" />
</remote-repository>
<remote-repository>
<option name="id" value="jboss.community" />
<option name="name" value="JBoss Community repository" />
<option name="url" value="https://repository.jboss.org/nexus/content/repositories/public/" />
</remote-repository>
</component>
</project>

View File

@ -1,8 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ProjectModuleManager">
<modules>
<module fileurl="file://$PROJECT_DIR$/Assignment 2 Java.iml" filepath="$PROJECT_DIR$/Assignment 2 Java.iml" />
</modules>
</component>
</project>

View File

@ -1,27 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<module type="JAVA_MODULE" version="4"> <module type="JAVA_MODULE" version="4">
<component name="NewModuleRootManager" inherit-compiler-output="true"> <component name="AdditionalModuleElements">
<exclude-output /> <content url="file://$MODULE_DIR$" dumb="true">
<javadoc-paths>
<root url="file://$MODULE_DIR$/libs" />
</javadoc-paths>
<content url="file://$MODULE_DIR$">
<sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" /> <sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" />
</content> </content>
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />
<orderEntry type="module-library" exported="">
<library>
<CLASSES>
<root url="file://$MODULE_DIR$/libs" />
</CLASSES>
<JAVADOC />
<SOURCES>
<root url="file://$MODULE_DIR$/libs" />
</SOURCES>
<jarDirectory url="file://$MODULE_DIR$/libs" recursive="false" />
<jarDirectory url="file://$MODULE_DIR$/libs" recursive="false" type="SOURCES" />
</library>
</orderEntry>
</component> </component>
</module> </module>

Binary file not shown.

Binary file not shown.

104
pom.xml Normal file
View File

@ -0,0 +1,104 @@
<?xml version="1.0" encoding="UTF-8"?>
<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>
<groupId>ca.brock.3P95.Assignemnt2</groupId>
<artifactId>FemboyInternational</artifactId>
<version>0.69.420</version>
<properties>
<maven.compiler.source>17</maven.compiler.source>
<maven.compiler.target>17</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<build>
<pluginManagement>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.1</version>
</plugin>
</plugins>
</pluginManagement>
</build>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>io.opentelemetry</groupId>
<artifactId>opentelemetry-bom</artifactId>
<version>1.32.0</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<dependency>
<groupId>io.opentelemetry</groupId>
<artifactId>opentelemetry-api</artifactId>
</dependency>
<dependency>
<groupId>io.opentelemetry</groupId>
<artifactId>opentelemetry-sdk</artifactId>
</dependency>
<dependency>
<groupId>io.opentelemetry</groupId>
<artifactId>opentelemetry-sdk-metrics</artifactId>
</dependency>
<dependency>
<groupId>io.opentelemetry</groupId>
<artifactId>opentelemetry-exporter-logging</artifactId>
</dependency>
<dependency>
<groupId>io.opentelemetry</groupId>
<artifactId>opentelemetry-exporter-otlp</artifactId>
</dependency>
<dependency>
<groupId>io.opentelemetry</groupId>
<artifactId>opentelemetry-exporter-otlp-common</artifactId>
</dependency>
<dependency>
<groupId>io.opentelemetry</groupId>
<artifactId>opentelemetry-exporter-jaeger-proto</artifactId>
</dependency>
<dependency>
<groupId>io.opentelemetry</groupId>
<artifactId>opentelemetry-sdk-extension-autoconfigure</artifactId>
</dependency>
<dependency>
<groupId>io.opentelemetry</groupId>
<artifactId>opentelemetry-sdk-extension-autoconfigure-spi</artifactId>
</dependency>
<!-- https://mvnrepository.com/artifact/io.opentelemetry/opentelemetry-semconv -->
<dependency>
<!-- Not managed by opentelemetry-bom -->
<groupId>io.opentelemetry.semconv</groupId>
<artifactId>opentelemetry-semconv</artifactId>
<version>1.22.0-alpha</version>
</dependency>
<!-- https://mvnrepository.com/artifact/io.opentelemetry.javaagent/opentelemetry-javaagent -->
<!-- <dependency>-->
<!-- <groupId>io.opentelemetry.javaagent</groupId>-->
<!-- <artifactId>opentelemetry-javaagent</artifactId>-->
<!-- <version>1.31.0</version>-->
<!-- <scope>runtime</scope>-->
<!-- </dependency>-->
<!-- https://mvnrepository.com/artifact/io.opentelemetry.javaagent/opentelemetry-javaagent-api -->
<!-- <dependency>-->
<!-- <groupId>io.opentelemetry.javaagent</groupId>-->
<!-- <artifactId>opentelemetry-javaagent-api</artifactId>-->
<!-- <version>0.16.1</version>-->
<!-- <scope>runtime</scope>-->
<!-- </dependency>-->
<dependency>
<groupId>org.lz4</groupId>
<artifactId>lz4-java</artifactId>
<version>1.8.0</version>
</dependency>
</dependencies>
</project>

View File

@ -41,12 +41,15 @@ public class Client {
public void close(){ public void close(){
try { try {
out.writeByte(FileUtil.COMMAND.CLOSE.type);
out.flush();
in.close(); in.close();
out.close(); out.close();
serverConnection.close(); serverConnection.close();
} catch (Exception e){ } catch (Exception e){
ExceptionLogger.log(e); ExceptionLogger.log(e);
} }
System.out.println("Disconnected!");
} }
public static void main(String[] args) { public static void main(String[] args) {

View File

@ -1,5 +1,9 @@
package server; package server;
import io.opentelemetry.api.trace.Span;
import io.opentelemetry.api.trace.Tracer;
import io.opentelemetry.context.Context;
import io.opentelemetry.context.Scope;
import net.jpountz.xxhash.StreamingXXHash64; import net.jpountz.xxhash.StreamingXXHash64;
import shared.ArrayData; import shared.ArrayData;
import shared.FileUtil; import shared.FileUtil;
@ -7,6 +11,7 @@ import shared.FileUtil;
import java.io.*; import java.io.*;
import java.nio.file.Files; import java.nio.file.Files;
import java.nio.file.Paths; import java.nio.file.Paths;
import java.util.concurrent.TimeUnit;
public class ChunkedCompressedChecksumFileReader { public class ChunkedCompressedChecksumFileReader {
@ -22,14 +27,24 @@ public class ChunkedCompressedChecksumFileReader {
this.seed = seed; this.seed = seed;
} }
public FileHeader readChunk() throws IOException { public FileHeader readChunk(Tracer trace, Span sp) throws IOException {
//Span gf = trace.spanBuilder("Chunk Read").setParent(Context.current().with(sp)).startSpan();
FileHeader header = readHeader(); FileHeader header = readHeader();
if (header.getUncompressed() == 0) //try (Scope scope = gf.makeCurrent()) {
return header; if (header.getUncompressed() == 0)
byte[] data = readSome(header); return header;
byte[] decompressed = decompress(header, data); sp.addEvent("Read Data");
hash(header, decompressed); byte[] data = readSome(header);
fileOutputWriter.write(decompressed, 0, decompressed.length); sp.addEvent("Decompress Data");
byte[] decompressed = decompress(header, data);
sp.addEvent("Hash");
hash(header, decompressed);
sp.addEvent("Write");
fileOutputWriter.write(decompressed, 0, decompressed.length);
sp.addEvent("End");
// } finally {
// gf.end();
// }
return header; return header;
} }

View File

@ -4,6 +4,7 @@ import io.opentelemetry.api.trace.Span;
import io.opentelemetry.api.trace.SpanBuilder; import io.opentelemetry.api.trace.SpanBuilder;
import io.opentelemetry.api.trace.Tracer; import io.opentelemetry.api.trace.Tracer;
import io.opentelemetry.context.Context; import io.opentelemetry.context.Context;
import io.opentelemetry.context.Scope;
import shared.ExceptionLogger; import shared.ExceptionLogger;
import shared.FileUtil; import shared.FileUtil;
@ -17,22 +18,21 @@ public class Connection implements Runnable {
private final Server server; private final Server server;
private DataOutputStream out; private DataOutputStream out;
private DataInputStream in; private DataInputStream in;
private Tracer trace;
private Span fileSend; private Span fileSend;
public Connection(Server server, Tracer trace, Span parent, Socket clientSocket) { public Connection(Server server, Tracer trace, Span parent, Socket clientSocket) {
this.server = server; this.server = server;
this.clientSocket = clientSocket; this.clientSocket = clientSocket;
this.trace = trace;
try { try {
out = new DataOutputStream(new BufferedOutputStream(clientSocket.getOutputStream())); out = new DataOutputStream(new BufferedOutputStream(clientSocket.getOutputStream()));
in = new DataInputStream(new BufferedInputStream(clientSocket.getInputStream())); in = new DataInputStream(new BufferedInputStream(clientSocket.getInputStream()));
} catch (Exception e) { } catch (Exception e) {
ExceptionLogger.log(e); ExceptionLogger.log(e);
} }
parent.addEvent("Connection Established", System.nanoTime(), TimeUnit.NANOSECONDS); parent.addEvent("Connection Established");
SpanBuilder sb = trace.spanBuilder("New Connection"); SpanBuilder sb = trace.spanBuilder("New Connection");
Context ctx = Context.current();
parent.storeInContext(ctx);
sb.setParent(ctx);
sb.setAttribute("INetAddress", clientSocket.getInetAddress().toString()); sb.setAttribute("INetAddress", clientSocket.getInetAddress().toString());
sb.setAttribute("Port", clientSocket.getPort()); sb.setAttribute("Port", clientSocket.getPort());
sb.setAttribute("LocalPort", clientSocket.getLocalPort()); sb.setAttribute("LocalPort", clientSocket.getLocalPort());
@ -41,19 +41,37 @@ public class Connection implements Runnable {
@Override @Override
public void run() { public void run() {
while (server.isRunning()) { try (Scope scope = fileSend.makeCurrent()) {
if (!clientSocket.isConnected()) int filesReceived = 0;
break; while (server.isRunning()) {
try { System.out.println("Hello " + clientSocket.isConnected());
if (in.available() > 0) { if (!clientSocket.isConnected()) {
byte command = in.readByte(); System.out.println("Client Disconnected");
break;
if (command == FileUtil.COMMAND.WRITE.type) }
FileUtil.receive(in, fileSend); try {
if (in.available() > 0) {
fileSend.addEvent("File Received");
Span fileIn = trace.spanBuilder("File Received").setAttribute("Files Received", filesReceived).startSpan();
try (Scope s = fileIn.makeCurrent()){
byte command = in.readByte();
if (command == FileUtil.COMMAND.CLOSE.type) {
System.out.println("Client sent disconnect signal!");
break;
}
if (command == FileUtil.COMMAND.WRITE.type)
FileUtil.receive(in, trace, fileIn);
} finally {
fileIn.end();
}
}
} catch (IOException e) {
throw new RuntimeException(e);
} }
} catch (IOException e) {
throw new RuntimeException(e);
} }
} finally {
fileSend.end();
} }
try { try {
out.close(); out.close();

View File

@ -3,7 +3,9 @@ package server;
import io.opentelemetry.api.OpenTelemetry; import io.opentelemetry.api.OpenTelemetry;
import io.opentelemetry.api.trace.Span; import io.opentelemetry.api.trace.Span;
import io.opentelemetry.api.trace.SpanBuilder; import io.opentelemetry.api.trace.SpanBuilder;
import io.opentelemetry.api.trace.SpanKind;
import io.opentelemetry.api.trace.Tracer; import io.opentelemetry.api.trace.Tracer;
import io.opentelemetry.context.Scope;
import shared.ExceptionLogger; import shared.ExceptionLogger;
import shared.OTelUtils; import shared.OTelUtils;
@ -25,12 +27,25 @@ public class Server {
public Server() { public Server() {
Tracer main = ot.getTracer("Main Server", "0.69"); Tracer main = ot.getTracer("Main Server", "0.69");
System.out.println("Starting server"); Span sbs = main.spanBuilder("Start Server").setAttribute("Server Port", SERVER_PORT).startSpan();
SpanBuilder sb = main.spanBuilder("Start Server"); try (Scope scope = sbs.makeCurrent()) {
Span sbs = sb.startSpan(); System.out.println("Starting server");
try {
sbs.addEvent("Server Start", System.nanoTime(), TimeUnit.NANOSECONDS); sbs.addEvent("Server Start", System.nanoTime(), TimeUnit.NANOSECONDS);
ServerSocket serverSocket = new ServerSocket(SERVER_PORT); ServerSocket serverSocket = new ServerSocket(SERVER_PORT);
Runtime.getRuntime().addShutdownHook(new Thread() {
@Override
public void run() {
System.out.println("Closing Server");
running = false;
sbs.end();
executor.shutdown();
try {
serverSocket.close();
} catch (IOException e) {
throw new RuntimeException(e);
}
}
});
System.out.println("Server Started"); System.out.println("Server Started");
while (running) while (running)
@ -40,8 +55,12 @@ public class Server {
} catch (IOException e) { } catch (IOException e) {
sbs.recordException(e); sbs.recordException(e);
ExceptionLogger.log(e); ExceptionLogger.log(e);
} finally {
sbs.end();
} }
System.out.println("Closing thread pool");
executor.shutdown(); executor.shutdown();
System.out.println("Server exited!");
} }
public boolean isRunning(){ public boolean isRunning(){

View File

@ -2,6 +2,7 @@ package shared;
import client.ChunkedCompressedChecksumFileWriter; import client.ChunkedCompressedChecksumFileWriter;
import io.opentelemetry.api.trace.Span; import io.opentelemetry.api.trace.Span;
import io.opentelemetry.api.trace.Tracer;
import net.jpountz.lz4.LZ4Compressor; import net.jpountz.lz4.LZ4Compressor;
import net.jpountz.lz4.LZ4Factory; import net.jpountz.lz4.LZ4Factory;
import net.jpountz.lz4.LZ4FastDecompressor; import net.jpountz.lz4.LZ4FastDecompressor;
@ -28,7 +29,8 @@ public class FileUtil {
public static final XXHash64 HASH_64 = XX_HASH_FACTORY.hash64(); public static final XXHash64 HASH_64 = XX_HASH_FACTORY.hash64();
public enum COMMAND { public enum COMMAND {
WRITE((byte) 1); CLOSE((byte) 1),
WRITE((byte) 2);
public final byte type; public final byte type;
COMMAND(byte type) { COMMAND(byte type) {
@ -57,21 +59,26 @@ public class FileUtil {
} }
} }
public static void receive(DataInputStream dataIn, Span fs) { public static void receive(DataInputStream dataIn, Tracer trace, Span sp) {
try { try {
String path = createPath(dataIn.readUTF()); String path = createPath(dataIn.readUTF());
fs.addEvent("Sending file " + path, System.nanoTime(), TimeUnit.NANOSECONDS); sp.addEvent("Sending file " + path);
System.out.println("Writing to file: " + path); System.out.println("Writing to file: " + path);
sp.setAttribute("File", path);
sp.addEvent("File Received");
ChunkedCompressedChecksumFileReader reader = new ChunkedCompressedChecksumFileReader(dataIn, path, FileUtil.SEED); ChunkedCompressedChecksumFileReader reader = new ChunkedCompressedChecksumFileReader(dataIn, path, FileUtil.SEED);
// ugh I want while(reader.readChunk().getUncompressed()); but it makes warnings!!! // ugh I want while(reader.readChunk().getUncompressed()); but it makes warnings!!!
while(true) { while(true) {
if (reader.readChunk().getUncompressed() == 0) if (reader.readChunk(trace, sp).getUncompressed() == 0) {
sp.addEvent("Chunk Read");
break; break;
}
} }
reader.close(); reader.close();
System.out.println("Writing " + path + " complete"); System.out.println("Writing " + path + " complete");
sp.addEvent("File Written");
} catch (Exception e) { } catch (Exception e) {
ExceptionLogger.log(e); ExceptionLogger.log(e);
} }

View File

@ -8,7 +8,7 @@ import io.opentelemetry.context.propagation.TextMapPropagator;
import io.opentelemetry.exporter.logging.LoggingMetricExporter; import io.opentelemetry.exporter.logging.LoggingMetricExporter;
import io.opentelemetry.exporter.logging.LoggingSpanExporter; import io.opentelemetry.exporter.logging.LoggingSpanExporter;
import io.opentelemetry.exporter.logging.SystemOutLogRecordExporter; import io.opentelemetry.exporter.logging.SystemOutLogRecordExporter;
import io.opentelemetry.javaagent.shaded.io.opentelemetry.semconv.ResourceAttributes; import io.opentelemetry.exporter.otlp.trace.OtlpGrpcSpanExporter;
import io.opentelemetry.sdk.OpenTelemetrySdk; import io.opentelemetry.sdk.OpenTelemetrySdk;
import io.opentelemetry.sdk.logs.SdkLoggerProvider; import io.opentelemetry.sdk.logs.SdkLoggerProvider;
import io.opentelemetry.sdk.logs.export.BatchLogRecordProcessor; import io.opentelemetry.sdk.logs.export.BatchLogRecordProcessor;
@ -17,11 +17,13 @@ import io.opentelemetry.sdk.metrics.export.PeriodicMetricReader;
import io.opentelemetry.sdk.resources.Resource; import io.opentelemetry.sdk.resources.Resource;
import io.opentelemetry.sdk.trace.SdkTracerProvider; import io.opentelemetry.sdk.trace.SdkTracerProvider;
import io.opentelemetry.sdk.trace.export.SimpleSpanProcessor; import io.opentelemetry.sdk.trace.export.SimpleSpanProcessor;
import io.opentelemetry.sdk.trace.export.SpanExporter;
import io.opentelemetry.semconv.ResourceAttributes;
public class OTelUtils { public class OTelUtils {
public static OpenTelemetry create(){ public static OpenTelemetry createLogger(){
Resource resource = Resource.getDefault().toBuilder().put(ResourceAttributes.SERVICE_NAME.getKey(), "cum").put(ResourceAttributes.SERVICE_VERSION.getKey(), "0.1.0").build(); Resource resource = Resource.getDefault().toBuilder().put(ResourceAttributes.SERVICE_NAME, "cum").put(ResourceAttributes.SERVICE_VERSION, "0.1.0").build();
SdkTracerProvider sdkTracerProvider = SdkTracerProvider.builder() SdkTracerProvider sdkTracerProvider = SdkTracerProvider.builder()
.addSpanProcessor(SimpleSpanProcessor.create(LoggingSpanExporter.create())) .addSpanProcessor(SimpleSpanProcessor.create(LoggingSpanExporter.create()))
@ -46,4 +48,34 @@ public class OTelUtils {
.buildAndRegisterGlobal(); .buildAndRegisterGlobal();
} }
public static OpenTelemetry create(){
Resource resource = Resource.getDefault().toBuilder().put(ResourceAttributes.SERVICE_NAME.getKey(), "cum").put(ResourceAttributes.SERVICE_VERSION.getKey(), "0.1.0").build();
SpanExporter otlpExporter = OtlpGrpcSpanExporter.builder()
.setEndpoint("http://sc.on.underlying.skynet.tpgc.me:4317")
.build();
SdkTracerProvider sdkTracerProvider = SdkTracerProvider.builder()
.addSpanProcessor(SimpleSpanProcessor.create(otlpExporter))
.setResource(resource)
.build();
SdkMeterProvider sdkMeterProvider = SdkMeterProvider.builder()
.registerMetricReader(PeriodicMetricReader.builder(LoggingMetricExporter.create()).build())
.setResource(resource)
.build();
SdkLoggerProvider sdkLoggerProvider = SdkLoggerProvider.builder()
.addLogRecordProcessor(BatchLogRecordProcessor.builder(SystemOutLogRecordExporter.create()).build())
.setResource(resource)
.build();
return OpenTelemetrySdk.builder()
.setTracerProvider(sdkTracerProvider)
.setMeterProvider(sdkMeterProvider)
.setLoggerProvider(sdkLoggerProvider)
.setPropagators(ContextPropagators.create(TextMapPropagator.composite(W3CTraceContextPropagator.getInstance(), W3CBaggagePropagator.getInstance())))
.buildAndRegisterGlobal();
}
} }

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -0,0 +1,13 @@
shared/ExceptionLogger.class
server/Server$1.class
shared/FileUtil.class
server/Server.class
server/Connection.class
shared/ArrayData.class
server/ChunkedCompressedChecksumFileReader.class
client/ChunkedCompressedChecksumFileWriter.class
shared/FileUtil$InvalidUsageException.class
shared/OTelUtils.class
client/Client.class
server/FileHeader.class
shared/FileUtil$COMMAND.class

View File

@ -0,0 +1,10 @@
/home/brett/Documents/Brock/CS 3P95/Assignments/Assignment 2 Java/src/main/java/client/Client.java
/home/brett/Documents/Brock/CS 3P95/Assignments/Assignment 2 Java/src/main/java/server/FileHeader.java
/home/brett/Documents/Brock/CS 3P95/Assignments/Assignment 2 Java/src/main/java/client/ChunkedCompressedChecksumFileWriter.java
/home/brett/Documents/Brock/CS 3P95/Assignments/Assignment 2 Java/src/main/java/server/ChunkedCompressedChecksumFileReader.java
/home/brett/Documents/Brock/CS 3P95/Assignments/Assignment 2 Java/src/main/java/shared/ArrayData.java
/home/brett/Documents/Brock/CS 3P95/Assignments/Assignment 2 Java/src/main/java/server/Server.java
/home/brett/Documents/Brock/CS 3P95/Assignments/Assignment 2 Java/src/main/java/server/Connection.java
/home/brett/Documents/Brock/CS 3P95/Assignments/Assignment 2 Java/src/main/java/shared/OTelUtils.java
/home/brett/Documents/Brock/CS 3P95/Assignments/Assignment 2 Java/src/main/java/shared/ExceptionLogger.java
/home/brett/Documents/Brock/CS 3P95/Assignments/Assignment 2 Java/src/main/java/shared/FileUtil.java