how can i determine the working directory a fatjar was invoked from - fatjar

I have a project which i have made into a fatjar. Gradle pus this into the /build/libs
I have gone to this directory and invoked the fatjar with a file as a param.
steps
cd /build/libs
java -jar .jar --execute script.groovy
this launches the Main-Class - a launcher class that reads the args from command line.
however what you get as the file name is 'script.groovy' and thats intended to be from the same directory as i have the jar file
Inside the class /fatjar however if you look at
System.getProperty("user.dir")
or
Path path = FileSystems.getDefault().getPath(".").toAbsolutePath()
they all report the path as the projectRoot directory - and not where the jar itself was run from (/build/libs)
inside your class, inside the fatjar, how do you determine the directory where the fatjar actually is when invoked from the command line?

I struggled a bit on this as well. You can find some hints in StartupInfoLogger.java from spring. I am using 2.1.5 spring boot version.
Here is some sample code.
public class MyTestFatJarMainClass {
public static void main(String[] args) {
SpringApplication.run(MyTestFatJarMainClass.class, args);
// The needed code start below
// The class is MyTestFatJarMainClass.class, but it can be any class in your app
ApplicationHome home = new ApplicationHome(MyTestFatJarMainClass.class);
String path = (home.getSource() != null) ? home.getSource().getAbsolutePath() : "";
// Now you got the path, it contains the jar file itself.
System.out.println("DINDA " + s + " path " + path);
}
}
You could also read String property = System.getProperty("user.dir");
Check which one of them can be useful for you.

Related

Start JavaFX application on new JVM via code [duplicate]

Can a Java application be loaded in a separate process using its name, as opposed to its location, in a platform independent manner?
I know you can execute a program via ...
Process process = Runtime.getRuntime().exec( COMMAND );
... the main issue of this method is that such calls are then platform specific.
Ideally, I'd wrap a method into something as simple as...
EXECUTE.application( CLASS_TO_BE_EXECUTED );
... and pass in the fully qualified name of an application class as CLASS_TO_BE_EXECUTED.
This is a synthesis of some of the other answers that have been provided. The Java system properties provide enough information to come up with the path to the java command and the classpath in what, I think, is a platform independent way.
public final class JavaProcess {
private JavaProcess() {}
public static int exec(Class klass, List<String> args) throws IOException,
InterruptedException {
String javaHome = System.getProperty("java.home");
String javaBin = javaHome +
File.separator + "bin" +
File.separator + "java";
String classpath = System.getProperty("java.class.path");
String className = klass.getName();
List<String> command = new LinkedList<String>();
command.add(javaBin);
command.add("-cp");
command.add(classpath);
command.add(className);
if (args != null) {
command.addAll(args);
}
ProcessBuilder builder = new ProcessBuilder(command);
Process process = builder.inheritIO().start();
process.waitFor();
return process.exitValue();
}
}
You would run this method like so:
int status = JavaProcess.exec(MyClass.class, args);
I thought it made sense to pass in the actual class rather than the String representation of the name since the class has to be in the classpath anyways for this to work.
Two hints:
System.getProperty("java.home") + "/bin/java" gives you a path to the java executable.
((URLClassLoader) Thread.currentThread().getContextClassLoader()).getURL() helps you to reconstruct the classpath of current application.
Then your EXECUTE.application is just (pseudocode):
Process.exec(javaExecutable, "-classpath", urls.join(":"), CLASS_TO_BE_EXECUTED)
This might be an overkill for you, but Project Akuma does what you want and more.
I found it via this entry at Kohsuke's (one of Sun's rock start programmers) fabulously useful blog.
Expanding on #stepancheg's answer the actual code would look like so (in the form of a test).
import org.junit.Test;
import java.io.File;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.Arrays;
import java.util.stream.Collectors;
public class SpinningUpAJvmTest {
#Test
public void shouldRunAJvm() throws Exception {
String classpath = Arrays.stream(((URLClassLoader) Thread.currentThread().getContextClassLoader()).getURLs())
.map(URL::getFile)
.collect(Collectors.joining(File.pathSeparator));
Process process = new ProcessBuilder(
System.getProperty("java.home") + "/bin/java",
"-classpath",
classpath,
MyMainClass.class.getName()
// main class arguments go here
)
.inheritIO()
.start();
int exitCode = process.waitFor();
System.out.println("process stopped with exitCode " + exitCode);
}
}
Did you check out the ProcessBuilder API? It's available since 1.5
http://java.sun.com/javase/6/docs/api/java/lang/ProcessBuilder.html
public abstract class EXECUTE {
private EXECUTE() { /* Procedural Abstract */ }
public static Process application( final String CLASS_TO_BE_EXECUTED ) {
final String EXEC_ARGUMENT
= new StringBuilder().
append( java.lang.System.getProperty( "java.home" ) ).
append( java.io.File.separator ).
append( "bin" ).
append( java.io.File.separator ).
append( "java" ).
append( " " ).
append( new java.io.File( "." ).getAbsolutePath() ).
append( java.io.File.separator ).
append( CLASS_TO_BE_EXECUTED ).
toString();
try {
return Runtime.getRuntime().exec( EXEC_ARGUMENT );
} catch ( final Exception EXCEPTION ) {
System.err.println( EXCEPTION.getStackTrace() );
}
return null;
}
}
Do you really have to launch them natively? Could you just call their "main" methods directly? The only special thing about main is that the VM launcher calls it, nothing stops you from calling main yourself.
Following on what TofuBeer had to say: Are you sure you really need to fork off another JVM? The JVM has really good support for concurrency these days, so you can get a lot of functionality for relatively cheap by just spinning off a new Thread or two (that may or may not require calling into Foo#main(String[])). Check out java.util.concurrent for more info.
If you decide to fork, you set yourself up for a bit of complexity related to finding required resources. That is, if your app is changing frequently and depends upon a bunch of jar files, you'll need to keep track of them all so that they can be passed out to the classpath arg. Additionally, such an approach requires to to infer both the location of the (currently executing) JVM (which may not be accurate) and the location of the current classpath (which is even less likely to be accurate, depending upon the way that the spawning Thread has been invoked - jar, jnlp, exploded .classes dir, some container, etc.).
On the other hand, linking into static #main methods has its pitfalls as well. static modifiers have a nasty tendency of leaking into other code and are generally frowned upon by design-minded folks.
A problem that occurs when you run this from a java GUI is it runs in the background.
So you cannot see the command prompt at all.
To get around this, you have to run the java.exe through "cmd.exe" AND "start".
I dont know why, but if you put "cmd /c start" infront it shows the command prompt as it runs.
However, the problem with "start" is that if there is a space in the path to the application
(which the path to the java exe usually have as it is in
C:\Program Files\Java\jre6\bin\java.exe or similar),
then start just fails with "cannot find c:\Program"
So you have to put quotes around C:\Program Files\Java\jre6\bin\java.exe
Now start complains about parameters that you pass to java.exe:
"The system cannot find the file -cp."
Escaping the space in "Program Files" with a backslash also does not work.
So the idea is to not use space.
Generate a temporary file with the bat extension and then put your command with spaces in there
and run the bat.
However, running a bat through start, does not exit when done,
so you have to put "exit" at the end of the batch file.
This still seems yucky.
So, looking for alternatives, I have found that using quote space quote in the space of "Program Files" actually works with start.
In the EXECUTE class above change the string builder appends to:
append( "cmd /C start \"Some title\" " ).
append( java.lang.System.getProperty( "java.home" ).replaceAll(" ", "\" \"") ).
append( java.io.File.separator ).
append( "bin" ).
append( java.io.File.separator ).
append( "java" ).
append( " " ).
append( new java.io.File( "." ).getAbsolutePath() ).
append( java.io.File.separator ).
append( CLASS_TO_BE_EXECUTED ).

Connecting to SFTP via SSIS

I'm trying to connect to a SFTP server via an SSIS package. The package executes WinSCP with the following connection string in a .txt file:
open sftp://username:fc$#6444#example.com:22
However the package keeps failing without being able to connect. Is it something to do with the special characters in the password?
I am able to connect to a different SFTP if I replace the string so I know it must be something to do with the syntax above. I've tried putting double quotes around the string as follows without any success:
open "sftp://username:fc$#6444#example.com:22"
I had to do this too, for one of my work projects recently. We used the WinSCP .NET assembly inside an SSIS Scripting Task, as this is what WinSCP also recommends as the way to achieve SFTP using WinSCP in SSIS.
See this guide - Using WinSCP .NET Assembly from SQL Server Integration Services (SSIS). It walks you through the install and setup and also contains working sample code (after you change the script to your needs of course!).
Sample code - after you reference the WinSCPnet.dll assembly - is below.
using System;
using Microsoft.SqlServer.Dts.Runtime;
using Microsoft.SqlServer.Dts.Tasks.ScriptTask;
using System.AddIn;
using WinSCP;
namespace ST_5a30686e70c04c5a8a93729fd90b8c79.csproj
{
[AddIn("ScriptMain", Version = "1.0", Publisher = "", Description = "")]
public partial class ScriptMain : VSTARTScriptObjectModelBase
{
public void Main()
{
// Setup session options
SessionOptions sessionOptions = new SessionOptions
{
Protocol = Protocol.Sftp,
// To setup these variables, go to SSIS > Variables.
// To make them accessible from the script task, in the context menu of the task,
// choose Edit. On the Script task editor on Script page, select ReadOnlyVariables,
// and tick the below properties.
HostName = (string) Dts.Variables["User::HostName"].Value,
UserName = (string) Dts.Variables["User::UserName"].Value,
Password = (string) Dts.Variables["User::Password"].Value,
SshHostKeyFingerprint = (string) Dts.Variables["User::SshHostKeyFingerprint"].Value
};
try
{
using (Session session = new Session())
{
// As WinSCP .NET assembly has to be stored in GAC to be used with SSIS,
// you need to set path to WinSCP.exe explicitly, if using non-default location.
session.ExecutablePath = #"C:\winscp\winscp.exe";
// Connect
session.Open(sessionOptions);
// Upload files
TransferOptions transferOptions = new TransferOptions();
transferOptions.TransferMode = TransferMode.Binary;
TransferOperationResult transferResult;
transferResult = session.PutFiles(#"d:\toupload\*", "/home/user/", false, transferOptions);
// Throw on any error
transferResult.Check();
// Print results
bool fireAgain = false;
foreach (TransferEventArgs transfer in transferResult.Transfers)
{
Dts.Events.FireInformation(0, null,
string.Format("Upload of {0} succeeded", transfer.FileName),
null, 0, ref fireAgain);
}
}
Dts.TaskResult = (int)DTSExecResult.Success;
}
catch (Exception e)
{
Dts.Events.FireError(0, null,
string.Format("Error when using WinSCP to upload files: {0}", e),
null, 0);
Dts.TaskResult = (int)DTSExecResult.Failure;
}
}
}
}
Install WinSCP and then create a folder where you want a file from client or put the file.Then Open a Execute Process Task and then go to Expression tab and set the Executable and Arguments with below codes(Please change accordingly).
Write this code in notepad and save as winscp.txt at the path C:\path\to\winscp.txt.
Open sftp://Host_Name:Password#apacsftp01.mftservice.com/ -hostkey="ssh-rsa 2048 xxxxxxxxxxx...="
get -delete /home/client/Share/MediaData/Media_file.xlsx
exit

How can I get a gwt-maps-3.0 api jar compatible with java 1.5 compiler

I am working for a large company that changes slowly. We are deploying to a Weblogic 10.2 environment, and are stuck with java 1.5. That is not a problem with GWT libraries, but the downloaded version of gwt-maps-3.0.2b.gwt22.jar we have pulled down was built with a 1.6 compiler. Does anyone know if a 1.5 built version is available?
Baring that, is it possible to rebuild with the 1.5 compiler, since the source is in the jar? If so, does anyone have a build script to do so?
-- Some additional info
We are trying to upgrade some existing code, This is the first error that they ran into offshore. The compile error tat they got was:
o Error: “class file has wrong version 50.0, should be 49.0”
I checked the jar file using the following method.
built the following program:
import java.io.*;
public class CheckVersion {
public static void main(String[] args) throws IOException {
for (int i=0; i < args.length; ++i) {
checkVersion(args[i]);
}
}
private static void checkVersion(String classFileName) throws IOException {
DataInputStream in = new DataInputStream(new FileInputStream(classFileName));
int magicNo = in.readInt();
if (magicNo != 0xCAFEBABE) {
System.err.println(classFileName + " is not a valid class file name");
return;
}
int minor = in.readUnsignedShort();
int major = in.readUnsignedShort();
System.out.println(classFileName + ": " + major +"." + minor);
in.close();
}
}
extracted the jar file eg. "jar xvf gwt-maps3-0.2b.jar"
ran the following command: "find . -name *.class | xargs java CheckVersion | cut -d':' -f2 | sort -u"
You have to download sources from google code :
http://code.google.com/p/gwt-google-maps-v3/source/checkout
-- No this does not work. All versions on the page were built with 1.6
I was able to resolve this by downloading the source, commenting out the #Override annotations which in 1.5 require that method in the parent have an implementation, and recompiling the module.

Flex Mobile AIR Native Extension errors

I'm currently working on creating an Android ANE for native alert popups. I'm now at the point where I think my both my Java and AS3 code is good to go but I'm getting an error when I try to use it.
Main Thread (Suspended: TypeError: Error #1009: Cannot access a property or method of a null object reference.)
My problem is I'm really not sure where this error is coming from. My thinking is that I'm not building the ANE file correctly or something is wrong in my extension.xml file but I'm really not too sure.
I'm going to try to provide as much information as I can about how this project is set up. Right now I'm trying to use this ANE in a small, testing application.
First, the folder setup:
ANEextensions-
Alert_Java (holding my Java project)
(Android/Java created assets. Not sure if these are important or now. If so I will list them)
src
com
fa
ne
android
AlertContext.java
AlertExtension.java
ShowAlert.java
Alert_AS
bin
AlertAndroidAS.swc
src
Alert.as
extension.xml
I'm not going to bother posting my java code as I think it's correct. but if anyone who is willing to invest some time in helping me with this issue wants to take a look please let me know.
This is my extensions.xml file
<extension xmlns="http://ns.adobe.com/air/extension/2.5">
<id>com.fa.alerts</id>
<versionNumber>1.0</versionNumber>
<platforms>
<platform name="Android-ARM">
<applicationDeployment>
<nativeLibrary>AndroidAlert.jar</nativeLibrary>
<initializer>com.fa.ne.android.AlertExtension</initializer>
<finalizer>com.fa.ne.android.AlertExtension</finalizer>
</applicationDeployment>
</platform>
</platforms>
</extension>
And this is my Alert.as file:
package {
import flash.events.EventDispatcher;
import flash.external.ExtensionContext;
public class Alert extends EventDispatcher{
public static var extContext:ExtensionContext = null
public function Alert(){
super();
extContext = ExtensionContext.createExtensionContext("com.fa.alerts", null);
}
public static function androidAlert(aTitle:String, aMsg:String, aNeg:String = "Cancel", aPos:String = "Ok"):void{
extContext.call("showAlert", aTitle, aMsg, aNeg, aPos);
}
}
}
And this is my stub app I'm using to test
<?xml version="1.0" encoding="utf-8"?>
<s:View xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark" title="HomeView">
<fx:Script>
<![CDATA[
protected function spawnAne(event:MouseEvent):void{
var a:Alert = new Alert();
Alert.androidAlert("test","testing");
}
]]>
</fx:Script>
<fx:Declarations>
<!-- Place non-visual elements (e.g., services, value objects) here -->
</fx:Declarations>
<s:Button click="spawnAne(event)" />
</s:View>
Now clicking on that button is what causes the error.
I don't have any kind of swc or link between my testing app and the AS3 Alert_AS project. I'm using Flash Builder 4.6 to import the ANE file using the IDE tools.
To build my ANE I'm using a lightly modified bash script from this post: http://gotoandlearn.com/play.php?id=149 by Lee Brimelow
# path to YOUR Android SDK
export AIR_ANDROID_SDK_HOME="my sdk"
# path to the ADT tool in Flash Builder sdks
ADT="my adt"
# native project folder
NATIVE_FOLDER=Alert_Java
# AS lib folder
LIB_FOLDER=Alert_AS
# name of ANE file
ANE_NAME=AndroidAlert.ane
# JAR filename
JAR_NAME=AndroidAlert.jar
# cert path
CERT_NAME=cert.p12
# cert password
CERT_PASS=password
#===================================================================
echo "****** preparing ANE package sources *******"
rm ${ANE_NAME}
rm -rf ./build/ane
mkdir -p ./build/ane
mkdir -p ./build/ane/Android-ARM
mkdir -p ./build/ane/Android-ARM/res
# copy resources
cp -R ./${NATIVE_FOLDER}/res/* ./build/ane/Android-ARM/res
# create the JAR file
jar cf ./build/ane/Android-ARM/${JAR_NAME} -C ./${NATIVE_FOLDER}/bin .
# grab the extension descriptor and SWC library
cp ./${LIB_FOLDER}/src/extension.xml ./build/ane/
cp ./${LIB_FOLDER}/bin/*.swc ./build/ane/
unzip ./build/ane/*.swc -d ./build/ane
mv ./build/ane/library.swf ./build/ane/Android-ARM
echo "****** creating ANE package *******"
"$ADT" -package -storetype PKCS12 -keystore ./cert.p12 -storepass password -tsa none \
-target ane \
${ANE_NAME} \
./build/ane/extension.xml \
-swc ./build/ane/*.swc \
-platform Android-ARM \
-C ./build/ane/Android-ARM/ .
echo "****** ANE package created *******"
I know this is a bit long but any help would be greatly appreciated! And feel free to let me know if you need some more elaboration
Added Java code
I modified the original code a bit. I removed AlertExtension.java and moved the get context function to AlertContext.java. I was thinking this would solve my issue but I'm still getting the same result. Here is my code:
AlertContext.java, I'm assuming the createContext method is fired after var a:Alert = new Alert();
package com.fa.ne.android;
import java.util.Map;
import java.util.HashMap;
import com.adobe.fre.FREContext;
import com.adobe.fre.FREExtension;
import com.adobe.fre.FREFunction;
public class AlertContext extends FREContext implements FREExtension {
#Override
public FREContext createContext(String type){
return new AlertContext();
}
#Override
public void initialize(){
}
#Override
public void dispose() {
}
#Override
public Map<String, FREFunction> getFunctions() {
HashMap<String, FREFunction> functionMap = new HashMap<String, FREFunction>();
functionMap.put("showAlert", new ShowAlert());
return functionMap;
}
}
Here is my ShowAlert class
package com.fa.ne.android;
import android.app.Activity;
import android.app.AlertDialog.Builder;
import android.content.DialogInterface;
import android.content.DialogInterface.OnClickListener;
import com.adobe.fre.FREContext;
import com.adobe.fre.FREFunction;
import com.adobe.fre.FREInvalidObjectException;
import com.adobe.fre.FREObject;
import com.adobe.fre.FRETypeMismatchException;
import com.adobe.fre.FREWrongThreadException;
public class ShowAlert implements FREFunction {
#Override
public FREObject call(FREContext aContext, FREObject[] aPassedArgs) {
//get activity
Activity a = aContext.getActivity();
//grabbing context
final FREContext context = aContext;
try{
//getting the title and msg for alert as string
String title = aPassedArgs[0].getAsString();
String message = aPassedArgs[1].getAsString();
String negitive = aPassedArgs[3].getAsString();
String positive = aPassedArgs[4].getAsString();
//creating the alert builder with the activity
Builder builder = new Builder(a);
//setting the title and msg
builder.setTitle(title);
builder.setMessage(message);
//setting up buttons, negative and positive, each with an event so we can listen in AS3
//doing listeners inline
builder.setNegativeButton(negitive, new OnClickListener(){
#Override
public void onClick(DialogInterface dialog, int dig){
context.dispatchStatusEventAsync("nativeAlert", "negitive");
}
}).setNeutralButton(positive, new OnClickListener(){
#Override
public void onClick(DialogInterface dialog, int dig){
context.dispatchStatusEventAsync("positiveAlert", "positive");
}
});
//done building, time to alert and return
builder.create().show();
return FREObject.newObject(true);
//error handeling
} catch (IllegalStateException e) {
e.printStackTrace();
} catch (FRETypeMismatchException e) {
e.printStackTrace();
} catch (FREInvalidObjectException e) {
e.printStackTrace();
} catch (FREWrongThreadException e) {
e.printStackTrace();
}
return null;
}
}
Quick tip, create a function,
which tells you whether the extension is available.
public static function isSupported():Boolean
{
return extContext != null;
}
Hope this helps.
Also it's good to add a default implementation of the native extension, which can bee ritten entierly in actions script and will be used when you run the app in emulator.
For more information look here:
http://www.adobe.com/devnet/air/articles/extending-air.html
I can't really answer your question. I don't know Java (it reads like pseudo ActionScript for me heehhehee). However, this might offer you some help & someone you could refer back here who might spot the problem easily.
Piotr Walczyszyn created an Android native alert / push extension here:
http://www.riaspace.com/2011/09/as3c2dm-air-native-extension-to-push-notifications-with-c2dm/
In the comments I also found another person with an extensive tutorial for native alerts in iOS here: http://www.liquid-photo.com/2011/10/28/native-extension-for-adobe-air-and-ios-101/
I was reading the comments on Piotr's post and some things he said leads me to wonder if this line
extContext = ExtensionContext.createExtensionContext("com.fa.alerts", null);
might be causing/related to the problem
Hope this can help you and/or others.
Best of luck everyone!
Todd
...back to researching push notification options/viability
=D
I kept running into your problem too.
The ONLY tutorial I have been able to get to work (with some changes) has been the one found here.
http://www.adobe.com/devnet/air/articles/developing-native-extensions-air.html
I had to add -swf-version 13 to the flex library compiler.
And I had to add -tsa none to the adt command to build the ANE file.
Did You link the extension to the Android platform in FlashBuilder? Just adding it to the NativeExtension tab in "Flex Build Path" is not enough You also have to check the checkbox in
"Flex Build Packaging" >> "Google Andorid">> "Native Extension"
Also You can try to look at the diference and maby somthing will help from my porject:
NativeAlert

SSIS: Get any flat file source from folder and cache the name as a super global variable

I'm working in SSIS and Visual Studio 2008. When executed, I need to have the SSIS package perform the following tasks:
Check a folder for a file
If a file exists take the file and use it as the source for the flat file
Store the name of the file into a global variable that I can access in other parts of my package
The package will be run by some other script. Thus we need it to check for the file every time the package runs. We are trying to prevent the scenario where we have to monitor the folder and execute the package manually when the file appears.
Any suggestions?
The easiest way would be to set up a Foreach Loop container that has all the "work" of your package inside of it (optionally, you can it as a precursor step and use a conditional expression off of it). Assuming you have 2 variables called FileName (which is what you will have the value assigned to) and an InputFolder variable that contains the "where" we should be looking
ForEach Loop Editor
Collection tab:
Enumerator = Foreach File Enumerators
Expression: Directory = #[User:InputFolder]
FileSpec: "YD.*"
Retrieve file name
* Fully qualified
Variable Mappings tab:
Variable: User::FileName
Index: 0
You can also do this via a script task, if you'd like to see that, let me know.
EDIT
This script again assumes you have the variables InputFolder and FileName defined. Create a Script Task Component and check InputFolder as a read only variable, FileName as a read/write variable.
using System;
using System.Data;
using System.IO; // this needs to be added
using Microsoft.SqlServer.Dts.Runtime;
using System.Windows.Forms;
// namespace will vary
namespace ST_bc177fa7cb7d4faca15531cb700b7f11.csproj
{
[System.AddIn.AddIn("ScriptMain", Version = "1.0", Publisher = "", Description = "")]
public partial class ScriptMain : Microsoft.SqlServer.Dts.Tasks.ScriptTask.VSTARTScriptObjectModelBase
{
#region VSTA generated code
enum ScriptResults
{
Success = Microsoft.SqlServer.Dts.Runtime.DTSExecResult.Success,
Failure = Microsoft.SqlServer.Dts.Runtime.DTSExecResult.Failure
};
#endregion
public void Main()
{
string inputFolder;
string fileName;
inputFolder = Dts.Variables["InputFolder"].Value.ToString();
// File, if exists will look like YD.CCYYMMDD.hhmmss.done
string fileMask = "YD.*.done";
// this array will catch all the files matching a given pattern
string[] foundFiles = null;
foundFiles = System.IO.Directory.GetFiles(inputFolder, fileMask);
// Since there should be only one file, we will grab the zeroeth
// element, should it exist
if (foundFiles.Length > 0)
{
fileName = foundFiles[0];
// write the value to our global SSIS variable
Dts.Variables["FileName"].Value = fileName;
}
Dts.TaskResult = (int)ScriptResults.Success;
}
}
}
Here is a possible option. You can achieve this using the Foreach Loop container. Please find the example that I have provided below. Hopefully, that gives an idea.
Step-by-step process:
On the SSIS package, create 3 variables are shown in screenshot #1. Scope CheckFile represents the package name. Variable Folder will represent the folder that you would like to check for the file. Filename represents the file name to check for. Variable FilePath will be the global variable that you will need. It will be filled in with the file path value if the file exists, otherwise it will be empty.
On the package's Control Flow tab, place a Foreach Loop container and a Script Task. Script Task is to showcase that the variable retains the value after the Foreach Loop container execution is complete. Refer screenshot #2.
Configure ForEach Loop container as shown in screenshots #3 and #4.
Replace the Main() method within the Script Task with the code given under the Script task code section. This is to demonstrate the value retained by the variable FilePath.
Screenshots #5 shows no files exist in the path c:\temp\ and screenshot #6 shows the corresponding package execution.
Screenshots #7 shows the file TestFile.txt exists in the path c:\temp\ and screenshot #8 shows the corresponding package execution.
If you would like to process the file when it exists, you can place a Data Flow Task within the Foreach Loop container to do that.
Hope that helps.
Script task code:
C# code that can be used only in SSIS 2008 and above..
public void Main()
{
Variables varCollection = null;
Dts.VariableDispenser.LockForRead("User::FilePath");
Dts.VariableDispenser.GetVariables(ref varCollection);
if (String.IsNullOrEmpty(varCollection["User::FilePath"].Value.ToString()))
{
MessageBox.Show("File doesn't exist.");
}
else
{
MessageBox.Show("File " + varCollection["User::FilePath"].Value.ToString() + " exists.");
}
Dts.TaskResult = (int)ScriptResults.Success;
}
Screenshot #1:
Screenshot #2:
Screenshot #3:
Screenshot #4:
Screenshot #5:
Screenshot #6:
Screenshot #7:
Screenshot #8: