<commit_before>package edu.harvard.iq.dataverse.util;

import com.ocpsoft.pretty.PrettyContext;
import edu.harvard.iq.dataverse.settings.SettingsServiceBean;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.Locale;
import java.util.MissingResourceException;
import java.util.Properties;
import java.util.ResourceBundle;
import java.util.logging.Logger;
import javax.ejb.EJB;
import javax.ejb.Stateless;
import javax.inject.Named;

/**
 * System-wide configuration
 */
@Stateless
@Named
public class SystemConfig {

    private static final Logger logger = Logger.getLogger(SystemConfig.class.getCanonicalName());

    @EJB
    SettingsServiceBean settingsService;

    /**
     * A JVM option for the advertised fully qualified domain name (hostname) of
     * the Dataverse installation, such as "dataverse.example.com", which may
     * differ from the hostname that the server knows itself as.
     *
     * The equivalent in DVN 3.x was "dvn.inetAddress".
     */
    public static final String FQDN = "dataverse.fqdn";
    
    /**
     * A JVM option for specifying the "official" URL of the site. 
     * Unlike the FQDN option above, this would be a complete URL, 
     * with the protocol, port number etc. 
     */
    public static final String SITE_URL = "dataverse.siteUrl";

    /**
     * A JVM option for where files are stored on the file system.
     */
    public static final String FILES_DIRECTORY = "dataverse.files.directory";

    /**
     * A JVM option to override the number of minutes for which a password reset
     * token is valid ({@link #minutesUntilPasswordResetTokenExpires}).
     */
    private static final String PASSWORD_RESET_TIMEOUT_IN_MINUTES = "dataverse.auth.password-reset-timeout-in-minutes";

    /**
     * A common place to find the String for a sane Solr hostname:port
     * combination.
     */
    private String saneDefaultForSolrHostColonPort = "localhost:8983";

    /**
     * The default number of datafiles that we allow to be created through 
     * zip file upload.
     */
    private static final int defaultZipUploadFilesLimit = 1000; 

    /**
     * @todo Reconcile with getApplicationVersion on DataverseServiceBean.java
     * which we'd like to move to this class.
     */
    private static String appVersionString = null; 
    private static String buildNumberString = null; 
    
    public String getVersion() {
        return getVersion(false);
    }
    
    public String getVersion(boolean withBuildNumber) {
        
        if (appVersionString == null) {

            // The Version Number is no longer supplied in a .properties file - so
            // we can't just do 
            //  return BundleUtil.getStringFromBundle("version.number", null, ResourceBundle.getBundle("VersionNumber", Locale.US));
            //
            // Instead, we'll rely on Maven placing the version number into the
            // Manifest, and getting it from there:
            // (this is considered a better practice, and will also allow us
            // to maintain this number in only one place - the pom.xml file)
            // -- L.A. 4.0.2
            
            // One would assume, that once the version is in the MANIFEST.MF, 
            // as Implementation-Version:, it would be possible to obtain 
            // said version simply as 
            //    appVersionString = getClass().getPackage().getImplementationVersion();
            // alas - that's not working, for whatever reason. (perhaps that's 
            // only how it works with jar-ed packages; not with .war files).
            // People on the interwebs suggest that one should instead 
            // open the Manifest as a resource, then extract its attributes. 
            // There were some complications with that too. Plus, relying solely 
            // on the MANIFEST.MF would NOT work for those of the developers who 
            // are using "in place deployment" (i.e., where 
            // Netbeans runs their builds directly from the local target 
            // directory, bypassing the war file deployment; and the Manifest 
            // is only available in the .war file). For that reason, I am 
            // going to rely on the pom.properties file - it is placed into the
            // application directory before the war file is built; thus this 
            // scheme will work both setups.
            // So, long story short, I'm resorting to the convoluted steps below. 
            // It may look hacky, but it should actually be pretty solid and 
            // reliable. 
            
            
            // First, find the absolute path url of the application persistence file
            // always supplied with the Dataverse app:
            java.net.URL fileUrl = Thread.currentThread().getContextClassLoader().getResource("META-INF/persistence.xml");
            String filePath = null;


            if (fileUrl != null) {
                filePath = fileUrl.getFile();
                if (filePath != null) {
                    filePath = filePath.replaceFirst("/[^/]*$", "/");
                    // Using a relative path, find the location of the maven pom.properties file:
                    filePath = filePath.concat("../../../META-INF/maven/edu.harvard.iq/dataverse/pom.properties");
                    // (this will work for both local, in-place runs and war file deployments!)
                    
                    try {
                        InputStream mavenPropertiesInputStream = new FileInputStream(filePath);
                        
                        Properties mavenProperties = new Properties();
                        mavenProperties.load(mavenPropertiesInputStream);
                        appVersionString = mavenProperties.getProperty("version");                        
                    } catch (IOException ioex) {
                        logger.warning("caught IOException trying to read the Manifest");
                    }
                    
                } else {
                    logger.warning("Null file path representation of the location of persistence.xml in the webapp root directory!"); 
                }
            } else {
                logger.warning("Could not find the location of persistence.xml in the webapp root directory!");
            }

            
            if (appVersionString == null) {
                // still null? - defaulting to 4.0:    
                appVersionString = "4.UNKNOWN";
            }
        }
            
        if (withBuildNumber) {
            if (buildNumberString == null) {
                // (build number is still in a .properties file in the source tree; it only 
                // contains a real build number if this war file was built by 
                // Jenkins) 
                        
                try {
                    buildNumberString = ResourceBundle.getBundle("BuildNumber").getString("build.number");
                } catch (MissingResourceException ex) {
                    buildNumberString = null; 
                }
            }
            
            if (buildNumberString != null && !buildNumberString.equals("")) {
                return appVersionString + " build " + buildNumberString; 
            } 
        }        
        
        return appVersionString; 
    }

    public String getSolrHostColonPort() {
        String solrHostColonPort = settingsService.getValueForKey(SettingsServiceBean.Key.SolrHostColonPort, saneDefaultForSolrHostColonPort);<commit_msg>Fixing the version retrieval, for local dev. builds.<commit_after>package edu.harvard.iq.dataverse.util;

import com.ocpsoft.pretty.PrettyContext;
import edu.harvard.iq.dataverse.settings.SettingsServiceBean;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.Locale;
import java.util.MissingResourceException;
import java.util.Properties;
import java.util.ResourceBundle;
import java.util.logging.Logger;
import javax.ejb.EJB;
import javax.ejb.Stateless;
import javax.inject.Named;

/**
 * System-wide configuration
 */
@Stateless
@Named
public class SystemConfig {

    private static final Logger logger = Logger.getLogger(SystemConfig.class.getCanonicalName());

    @EJB
    SettingsServiceBean settingsService;

    /**
     * A JVM option for the advertised fully qualified domain name (hostname) of
     * the Dataverse installation, such as "dataverse.example.com", which may
     * differ from the hostname that the server knows itself as.
     *
     * The equivalent in DVN 3.x was "dvn.inetAddress".
     */
    public static final String FQDN = "dataverse.fqdn";
    
    /**
     * A JVM option for specifying the "official" URL of the site. 
     * Unlike the FQDN option above, this would be a complete URL, 
     * with the protocol, port number etc. 
     */
    public static final String SITE_URL = "dataverse.siteUrl";

    /**
     * A JVM option for where files are stored on the file system.
     */
    public static final String FILES_DIRECTORY = "dataverse.files.directory";

    /**
     * A JVM option to override the number of minutes for which a password reset
     * token is valid ({@link #minutesUntilPasswordResetTokenExpires}).
     */
    private static final String PASSWORD_RESET_TIMEOUT_IN_MINUTES = "dataverse.auth.password-reset-timeout-in-minutes";

    /**
     * A common place to find the String for a sane Solr hostname:port
     * combination.
     */
    private String saneDefaultForSolrHostColonPort = "localhost:8983";

    /**
     * The default number of datafiles that we allow to be created through 
     * zip file upload.
     */
    private static final int defaultZipUploadFilesLimit = 1000; 

    /**
     * @todo Reconcile with getApplicationVersion on DataverseServiceBean.java
     * which we'd like to move to this class.
     */
    private static String appVersionString = null; 
    private static String buildNumberString = null; 
    
    public String getVersion() {
        return getVersion(false);
    }
    
    public String getVersion(boolean withBuildNumber) {
        
        if (appVersionString == null) {

            // The Version Number is no longer supplied in a .properties file - so
            // we can't just do 
            //  return BundleUtil.getStringFromBundle("version.number", null, ResourceBundle.getBundle("VersionNumber", Locale.US));
            //
            // Instead, we'll rely on Maven placing the version number into the
            // Manifest, and getting it from there:
            // (this is considered a better practice, and will also allow us
            // to maintain this number in only one place - the pom.xml file)
            // -- L.A. 4.0.2
            
            // One would assume, that once the version is in the MANIFEST.MF, 
            // as Implementation-Version:, it would be possible to obtain 
            // said version simply as 
            //    appVersionString = getClass().getPackage().getImplementationVersion();
            // alas - that's not working, for whatever reason. (perhaps that's 
            // only how it works with jar-ed packages; not with .war files).
            // People on the interwebs suggest that one should instead 
            // open the Manifest as a resource, then extract its attributes. 
            // There were some complications with that too. Plus, relying solely 
            // on the MANIFEST.MF would NOT work for those of the developers who 
            // are using "in place deployment" (i.e., where 
            // Netbeans runs their builds directly from the local target 
            // directory, bypassing the war file deployment; and the Manifest 
            // is only available in the .war file). For that reason, I am 
            // going to rely on the pom.properties file, and use java.util.Properties 
            // to read it. We have to look for this file in 2 different places
            // depending on whether this is a .war file deployment, or a 
            // developers build. (the app-level META-INF is only populated when
            // a .war file is built; the "maven-archiver" directory, on the other 
            // hand, is only available when it's a local build deployment).
            // So, long story short, I'm resorting to the convoluted steps below. 
            // It may look hacky, but it should actually be pretty solid and 
            // reliable. 
            
            
            // First, find the absolute path url of the application persistence file
            // always supplied with the Dataverse app:
            java.net.URL fileUrl = Thread.currentThread().getContextClassLoader().getResource("META-INF/persistence.xml");
            String filePath = null;


            if (fileUrl != null) {
                filePath = fileUrl.getFile();
                if (filePath != null) {
                    InputStream mavenPropertiesInputStream = null;
                    String mavenPropertiesFilePath; 
                    Properties mavenProperties = new Properties();

                    
                    filePath = filePath.replaceFirst("/[^/]*$", "/");
                    // Using a relative path, find the location of the maven pom.properties file. 
                    // First, try to look for it in the app-level META-INF. This will only be 
                    // available if it's a war file deployment: 
                    mavenPropertiesFilePath = filePath.concat("../../../META-INF/maven/edu.harvard.iq/dataverse/pom.properties");                                     
                    
                    try {
                        mavenPropertiesInputStream = new FileInputStream(mavenPropertiesFilePath);
                    } catch (IOException ioex) {
                        // OK, let's hope this is a local dev. build. 
                        // In that case the properties file should be available in 
                        // the maven-archiver directory: 
                        
                        mavenPropertiesFilePath = filePath.concat("../../../../maven-archiver/pom.properties");
                        
                        // try again: 
                        
                        try {
                            mavenPropertiesInputStream = new FileInputStream(mavenPropertiesFilePath);
                        } catch (IOException ioex2) {
                            logger.warning("Failed to find and/or open for reading the pom.properties file.");
                            mavenPropertiesInputStream = null; 
                        }
                    }
                    
                    if (mavenPropertiesInputStream != null) {
                        try {
                            mavenProperties.load(mavenPropertiesInputStream);
                            appVersionString = mavenProperties.getProperty("version");                        
                        } catch (IOException ioex) {
                            logger.warning("caught IOException trying to read and parse the pom properties file.");
                        }
                    }
                    
                } else {
                    logger.warning("Null file path representation of the location of persistence.xml in the webapp root directory!"); 
                }
            } else {
                logger.warning("Could not find the location of persistence.xml in the webapp root directory!");
            }

            
            if (appVersionString == null) {
                // still null? - defaulting to 4.0:    
                appVersionString = "4.0";
            }
        }
            
        if (withBuildNumber) {
            if (buildNumberString == null) {
                // (build number is still in a .properties file in the source tree; it only 
                // contains a real build number if this war file was built by 
                // Jenkins) 
                        
                try {
                    buildNumberString = ResourceBundle.getBundle("BuildNumber").getString("build.number");
                } catch (MissingResourceException ex) {
                    buildNumberString = null; 
                }
            }
            
            if (buildNumberString != null && !buildNumberString.equals("")) {
                return appVersionString + " build " + buildNumberString; 
            } 
        }        
        
        return appVersionString; 
    }

    public String getSolrHostColonPort() {
        String solrHostColonPort = settingsService.getValueForKey(SettingsServiceBean.Key.SolrHostColonPort, saneDefaultForSolrHostColonPort);
{'fraction_non_alphanumeric': 0.07751433808313132, 'fraction_numerical': 0.0019511618281795068, 'mean_word_length': 1.7650809220205983, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 3, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 8}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 1, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '2368327', 'n_tokens_mistral': 4185, 'n_tokens_neox': 3881, 'n_words': 1421}